// ---------------------------------
// <span style="font-family: Arial, Helvetica, sans-serif;">服务器</span>
#include <WinSock2.h> #pragma comment(lib, "ws2_32.lib") #include <stdio.h> #define PORT 8088 #define DATA_BUFSIZE 8192 typedef struct _IO_DATA { OVERLAPPED overLapped; WSABUF wsaBuf; CHAR chBuffer[DATA_BUFSIZE]; DWORD nBytesSend; DWORD nBytesRecv; } IO_DATA, * P_IO_DATA; typedef struct _HANDLE_DATA { SOCKET Socket; } HANDLE_DATA, * P_HANDLE_DATA; DWORD WINAPI workThread(LPVOID pCompletionPortID); int main() { SOCKET sListen; SOCKET sAccept; HANDLE hCompletionPort; SYSTEM_INFO sysInfo; P_HANDLE_DATA pHandleData; P_IO_DATA pIoData; DWORD nByteRecv; DWORD nFlags; DWORD nThreadID; WSADATA wsaData; int nReturn = 0; nReturn = WSAStartup(0x0202, &wsaData); // 为使代码简洁 nReturn后不进行错误检查。。。 // 创建一个完成端口 hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); if ( NULL == hCompletionPort) { return 0; } // 根据CPU数量,创建一定数量的工作线程,并将完成端口传给线程 GetSystemInfo(&sysInfo); for(int i = 0; i < (sysInfo.dwNumberOfProcessors * 2); i++) { HANDLE hThreadHandle; hThreadHandle = CreateThread(NULL, 0, workThread, hCompletionPort, 0, &nThreadID); CloseHandle(hThreadHandle); } sListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED); SOCKADDR_IN addrListen; addrListen.sin_family = AF_INET; addrListen.sin_port = htons(PORT); addrListen.sin_addr.s_addr = htonl(INADDR_ANY); nReturn = bind(sListen, (PSOCKADDR) &addrListen, sizeof(addrListen)); nReturn = listen(sListen, 5); printf("Service Start!\n"); while(TRUE) { sAccept = WSAAccept(sListen, NULL, NULL, NULL, 0); pHandleData = (P_HANDLE_DATA) GlobalAlloc(GPTR, sizeof(HANDLE_DATA)) pHandleData->Socket = sAccept; // 将连接sAccept和完成端口关联 if (NULL == CreateIoCompletionPort((HANDLE) sAccept, hCompletionPort, (DWORD) pHandleData, 0)) { printf("CreateIoCompletionPort failed with error %d\n", GetLastError()); return 0; } pIoData = (P_IO_DATA) GlobalAlloc(GPTR, sizeof(IO_DATA)); ZeroMemory(&(pIoData->overLapped), sizeof(OVERLAPPED)); pIoData->nBytesSend = 0; pIoData->nBytesRecv = 0; pIoData->wsaBuf.len = DATA_BUFSIZE; pIoData->wsaBuf.buf = pIoData->chBuffer; nFlags = 0; // 进行I/O操作 if (SOCKET_ERROR == WSARecv(sAccept, &(pIoData->wsaBuf), 1, &nByteRecv, &nFlags, &(pIoData->overLapped), NULL)) { if (WSAGetLastError() != ERROR_IO_PENDING) { printf("WSARecv() failed with error %d\n", WSAGetLastError()); return 0; } } } return 0; } DWORD WINAPI workThread(LPVOID pCompletionPortID) { HANDLE hCompletionPort = (HANDLE) pCompletionPortID; DWORD nByteTrans; P_HANDLE_DATA pHandleData; P_IO_DATA pIoData; DWORD nByteSend, nByteRecv; DWORD nFlags; while(TRUE) { // 依赖完成端口,接收有关I/O操作完成情况的通知 阻塞式,直到I/O操作成功或失败 GetQueuedCompletionStatus(hCompletionPort, &nByteTrans, (LPDWORD)&pHandleData, (LPOVERLAPPED *) &pIoData, INFINITE); if (0 == nByteTrans) { printf("Closing socket %d\n", pHandleData->Socket); closesocket(pHandleData->Socket); GlobalFree(pHandleData); GlobalFree(pIoData); continue; } if(0 == (pIoData->nBytesRecv)) { pIoData->nBytesRecv = nByteTrans; pIoData->nBytesSend = 0; } else { pIoData->nBytesSend += nByteTrans; } if ((pIoData->nBytesRecv) > (pIoData->nBytesSend)) { ZeroMemory(&(pIoData->overLapped), sizeof(OVERLAPPED)); pIoData->wsaBuf.buf = pIoData->chBuffer + pIoData->nBytesSend; pIoData->wsaBuf.len = pIoData->nBytesRecv - pIoData->nBytesSend; printf("Recv:%s\n", pIoData->wsaBuf.buf); if (SOCKET_ERROR == WSASend(pHandleData->Socket, &(pIoData->wsaBuf), 1, &nByteSend, 0, &(pIoData->overLapped), NULL)) { if (ERROR_IO_PENDING != WSAGetLastError()) { printf("WSASend() failed with error %d\n", WSAGetLastError()); return 0; } } } else { nFlags = 0; pIoData->nBytesRecv = 0; ZeroMemory(&(pIoData->overLapped), sizeof(OVERLAPPED)); pIoData->wsaBuf.len = DATA_BUFSIZE; pIoData->wsaBuf.buf = pIoData->chBuffer; if (SOCKET_ERROR == WSARecv(pHandleData->Socket, &(pIoData->wsaBuf), 1, &nByteRecv, &nFlags, &(pIoData->overLapped), NULL)) { if (ERROR_IO_PENDING != WSAGetLastError()) { printf("WSARecv() failed with error %d\n", WSAGetLastError()); return 0; } } } } }
=====================================================================================================
客户端
#include <WinSock2.h> #pragma comment(lib, "ws2_32.lib") #include <stdio.h> #define PORT 8088 #define BUF_SIZE 8192 int main() { WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); SOCKET sockConnect; sockConnect = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (INVALID_SOCKET == sockConnect) { return -1; } int nErrorCode = 0; int nMode; nErrorCode = ioctlsocket(sockConnect, FIONBIO, (u_long*)&nMode); if (SOCKET_ERROR == nErrorCode) { return -1; } sockaddr_in addrConnect; addrConnect.sin_family = AF_INET; addrConnect.sin_port = htons(PORT); addrConnect.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); int nAddrLen = sizeof(sockaddr_in); while(true) { nErrorCode = connect(sockConnect, (sockaddr*)&addrConnect, nAddrLen); if (SOCKET_ERROR == nErrorCode) { nErrorCode = WSAGetLastError(); if (WSAEWOULDBLOCK == nErrorCode || WSAEINVAL == nErrorCode) { Sleep(300); continue;// 继续连接 } else if (WSAEISCONN == nErrorCode) // 连接成功 { break; } else { printf("Connect Error! %ld", WSAGetLastError()); closesocket(sockConnect); WSACleanup(); return -1; } } } char chBuf[BUF_SIZE]; printf("Client Started OK!\n"); while(true) { while(true) { ZeroMemory(chBuf, BUF_SIZE); printf("This is Client Input:"); gets(chBuf); nErrorCode = send(sockConnect, chBuf, BUF_SIZE, 0); if (SOCKET_ERROR == nErrorCode) { nErrorCode = WSAGetLastError(); if (WSAEWOULDBLOCK == nErrorCode) { Sleep(800); continue; } else { printf("Send Eror! %ld", nErrorCode); closesocket(sockConnect); WSACleanup(); return -1; } } break; } while(true) { ZeroMemory(chBuf, BUF_SIZE); nErrorCode = recv(sockConnect, chBuf, BUF_SIZE, 0); if (SOCKET_ERROR == nErrorCode) { nErrorCode = WSAGetLastError(); if (WSAEWOULDBLOCK == nErrorCode) { Sleep(300); continue; } else if (WSAETIMEDOUT == nErrorCode || WSAENETDOWN == nErrorCode) { printf("Recv Error! %ld", nErrorCode); closesocket(sockConnect); WSACleanup(); return -1; } } printf("Recv--:%s\n", chBuf); break; } } return 0; }