IOCP如何获知某个客户端退出,并删除该客户端?
单机测试时 有两种情况。
有时一个客户端退出后,服务器当机,停止收发数据,新客户连接不上。
除此之外就是客户端退出后,比如有3个客户端,一个退出后还是显示3个客户端,并未删除退出客户。应该在哪里删除退出客户socket?
服务部分代码:(客户端的代码就是两个线程,一个不停收,一个不停发。)
GetSystemInfo(&SystemInfo); printf("CPU number : %d ...\n",SystemInfo.dwNumberOfProcessors); for(i = 0; i < SystemInfo.dwNumberOfProcessors * 2; i++) { HANDLE ThreadHandle; // 创建一个服务器工作者线程并通过完成端口连接它。; if ((ThreadHandle = CreateThread(NULL, 0, ServerWorkerThread, CompletionPort, 0, &ThreadID)) == NULL) { printf("CreateThread() failed with error %d\n", GetLastError()); return; } printf_s("CreateThread %d the end ... Enter Thread %d ...\n",i+1,i+1); // cout<<"CreateThread "<<i+1 <<" the end ... Enter Thread " <<i+1 <<" ...\n"; CloseHandle(ThreadHandle); // Close the thread handle } // Create a listening socket if ((Listen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET) { printf("WSASocket() failed with error %d\n", WSAGetLastError()); return; } printf("WSASocket the end ...\n"); InternetAddr.sin_family = AF_INET; InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY); InternetAddr.sin_port = htons(PORT); if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR) { printf("bind() failed with error %d\n", WSAGetLastError()); return; } printf("Bind the end ...\n"); // Prepare socket for listening if (listen(Listen, 5) == SOCKET_ERROR) { printf("listen() failed with error %d\n", WSAGetLastError()); return; } printf("Listen the end ...\nEnter the loop ...\n"); while(TRUE) { // 接受连接并分配该完成端口。; if ((Accept = WSAAccept(Listen, NULL, NULL, NULL, 0)) == SOCKET_ERROR) { printf("WSAAccept() failed with error %d\n", WSAGetLastError()); return; } printf("WSAAccept Loop ...\n"); // Create a socket information structure to associate with the socket if ((PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA))) == NULL) { printf("GlobalAlloc() failed with error %d\n", GetLastError()); return; } // accept原始完成端口socket; printf("Socket number %d connected\n", Accept); PerHandleData->Socket = Accept; accept_socket_number.push_back(Accept) ;// 添加新客户到LIST中 ; //将新套接字关联到IOCP上 ; if (CreateIoCompletionPort((HANDLE)Accept, CompletionPort, (DWORD) PerHandleData, 0) == NULL) { printf("CreateIoCompletionPort failed with error %d\n", GetLastError()); return; } printf("Set CreateIoCompletionPort end...\n"); // Create per I/O socket information structure to associate with the WSARecv call below. if ((PerIoData = (LPPER_IO_OPERATION_DATA) GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA) ) ) == NULL) { printf("GlobalAlloc() failed with error %d\n", GetLastError()); return; } ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->BytesSEND = 0; PerIoData->BytesRECV = 0; PerIoData->DataBuf.len = DATA_BUFSIZE; //初始化长度 ; PerIoData->DataBuf.buf = PerIoData->Buffer; //初始化大小 ; Flags = 0; if (WSARecv(Accept, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags, &(PerIoData->Overlapped), NULL) == SOCKET_ERROR) { if (WSAGetLastError() != ERROR_IO_PENDING) { printf("WSARecv() failed with error %d\n", WSAGetLastError()); return; } } struct sockaddr_in esa; int esalen = sizeof(esa); if(!getpeername(Accept, (struct sockaddr *)&esa, &esalen)) { printf( " New client IP:%s ", inet_ntoa(esa.sin_addr)); printf( " New client PORT:%d \n", ntohs(esa.sin_port)); }