NULL); 5在工作线程里等待完成事件 GetQueuedCompletionStatus函数原型

时间:2022-01-29 07:27:28

标签:

1详解完成端口根基使用

1创建完成端口

HANDLE iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);

参数其实就是-1,0,0,0. 最后一个参数代表的就是

NumberOfConcurrentThreads,就是允许应用同时执行的线程数量,

未来制止上下文切换,就是说让每个CPU只允许一个线程,设置为0

就是有几多措置惩罚惩罚器,就有几多事情线程。

原因就是如果一台机器有两个CPU(两核),如果让系统同时运行的

线程,多于本机CPU数量的话,就没什么意义,会浪费CPU名贵周期,

降低效率,得不偿掉。

然后会返回一个HANDLE 只要不是NULL就是成立完成端口告成。



2创建Socket绑定侦听 不久不多说

SOCKET lo_sock = INVALID_SOCKET; //创建掉败 if (iocp == NULL){ goto failed; } //创建一个线程  把IOCP传到线程函数里 h_threadS = CreateThread(NULL, 0, ServerThread, (LPVOID)iocp, 0, 0); // 防备内存泄露 CloseHandle(h_threadS); //end //创建socket lo_sock = socket(AF_INET,SOCK_STREAM,0); if (lo_sock == INVALID_SOCKET){ goto failed; } struct sockaddr_in addr; memset(&addr, 0, sizeof(addr)); addr.sin_addr.s_addr = inet_addr("127.0.0.1"); addr.sin_port = htons(port); addr.sin_family = AF_INET; int ret = bind(lo_sock, (const struct sockaddr*)&addr, sizeof(addr)); if (ret != 0){ printf("bind %s:%d error \n", "127.0.0.1", port); goto failed; } printf("bind %s:%d success \n", "127.0.0.1", port); printf("starting listener on %d\n", port); // SOMAXCONN 通过listen指定最大行列队伍长度 ret = listen(lo_sock, SOMAXCONN); if (ret != 0){ printf("listening on port failed\n"); goto failed; } printf("listening on success\n");




3在主线程里面侦听accept

struct sockaddr_in c_addr; int len = sizeof(c_addr); //没有client接入进来,线程会挂起  也就是梗阻 int client_fd = accept(lo_sock, (struct sockaddr*)&c_addr, &len); if (client_fd != INVALID_SOCKET){         //这里就是有新的socket连接了   printf("new client %s:%d coming\n", inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port));     }     else{ continue; } //生存会话信息   struct session* s = save_session(client_fd, inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port)); 将信息生存在一个存用户ip port  端口的布局体里面  这个布局体是这样的: /* 这个布局中界说 struct  session{ char c_ip[32]; //ip地点 int c_port;  //端口 int c_sock;  //socket句柄 int removed;//删除符号 struct  session * _next; //链表指针 }; */



4然后把获得的客户端socket绑定到iocp  

这段代码是在一个while(1)死循环里进行

先介绍下这个函数 和创建完成端口用的是一个API

HANDLE WINAPI CreateIoCompletionPort( __in  HANDLE FileHandle,  //这里就是客户连入的socket __in_opt HANDLE ExistingCompletionPort,//就是前面创建的完成端口, __in ULONG_PRT CompletionKey,//这个参数可以通报一个布局体,自界说的布局体                                //你只要把这个布局体传入,事情线程就可以取出来,                                // 我使用的是上面我界说的 布局体                               _in  DWORD DWORD NumberOfConcurrenThreads//上面说了,设置为0就行 ); //添加到这个完成端口 CreateIoCompletionPort((HANDLE)client_fd, iocp,(DWORD)s, 0); client_fd 就是上面或得的客户端socket 然后iocp完成端口,  s就是带有客户端会话信息的布局体


5投递一个异步recv请求

(就是报告完成端口,如果我这个客户端有包过,你要接收完成,然后报告我)

在这之前就要界说一个布局体作为标识表记标帜,因为启动的时候投递了很多的

I/O请求,要用一个标识表记标帜来绑定每一个I/O操纵,这样网络操纵完成后,

在通过这个标识表记标帜找到这组返回的数据:

必然要将WSAOVERLAPPED放第一个,其他的随意