连接:
http://blog.csdn.net/sodme/archive/2006/04/17/666062.aspx
http://lijinshui.bokee.com/3245440.html
http://blog.csdn.net/sodme/archive/2005/07/17/427405.aspx
http://blog.csdn.net/vieri_ch/archive/2005/10/11/499357.aspx
http://blog.csdn.net/SeaWave/archive/2006/05/21/747863.aspx
http://blog.csdn.net/xuwei2007/archive/2007/08/29/1764332.aspx
http://blog.csdn.net/juestSoftware/archive/2008/09/14/2855625.aspx
http://blog.csdn.net/wangandy7811/archive/2009/12/04/4930897.aspx
个人总结:
学习完成端口时,采用完成端口编写的服务器示例:
// CompletionPortServer.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include #include #include #pragma comment(lib, "ws2_32") #define DATA_BUFSIZE 10 #define RECV_POSTED 0 #define SEND_POSTED 1 typedef struct _PER_HANDLE_DATA { SOCKET Socket; SOCKADDR_STORAGE ClientAddr; // Other information useful to be associated with the handle } PER_HANDLE_DATA, * LPPER_HANDLE_DATA; typedef struct { OVERLAPPED Overlapped; WSABUF DataBuf; char Buffer[DATA_BUFSIZE]; int BufferLen; int OperationType; } PER_IO_DATA, *LPPER_IO_DATA; int StartWinsock( ) { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ printf("error = %d/n", WSAGetLastError()); return 0; } /* Confirm that the WinSock DLL supports 2.2.*/ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ WSACleanup( ); return 0; } printf("max socket is :%d/n", wsaData.iMaxSockets); return 1; } unsigned int WINAPI __stdcall ServerWorkerThread(LPVOID CompletionPortID) { // The requirements for the worker thread will be // discussed later. HANDLE CompletionPort = (HANDLE) CompletionPortID; DWORD BytesTransferred; LPPER_HANDLE_DATA PerHandleData; LPPER_IO_DATA PerIoData; DWORD SendBytes, RecvBytes; DWORD Flags; int iRet = 0; while(1) { // Wait for I/O to complete on any socket // associated with the completion port iRet = GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,(LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE); // First check to see if an error has occurred // on the socket; if so, close the // socket and clean up the per-handle data // and per-I/O operation data associated with // the socket if ( BytesTransferred == 0 && (PerIoData->OperationType == RECV_POSTED || PerIoData->OperationType == SEND_POSTED) ) { // A zero BytesTransferred indicates that the // socket has been closed by the peer, so // you should close the socket. Note: // Per-handle data was used to reference the // socket associated with the I/O operation. closesocket(PerHandleData->Socket); GlobalFree(PerHandleData); GlobalFree(PerIoData); continue; } if (iRet == 0) { closesocket(PerHandleData->Socket); GlobalFree(PerHandleData); GlobalFree(PerIoData); continue; } if (BytesTransferred == -10) { // A zero BytesTransferred indicates that the // socket has been closed by the peer, so // you should close the socket. Note: // Per-handle data was used to reference the // socket associated with the I/O operation. closesocket(PerHandleData->Socket); GlobalFree(PerHandleData); GlobalFree(PerIoData); continue; } // Service the completed I/O request. You can // determine which I/O request has just // completed by looking at the OperationType // field contained in the per-I/O operation data. if (PerIoData->OperationType == RECV_POSTED) { // Do something with the received data // in PerIoData->Buffer printf("%s/n",PerIoData->Buffer); //Response: // Set up the per-I/O operation data for the next // overlapped call ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.len = DATA_BUFSIZE; PerIoData->DataBuf.buf = PerIoData->Buffer; PerIoData->OperationType = SEND_POSTED; memset(PerIoData->Buffer, 0, DATA_BUFSIZE); strcpy_s(PerIoData->Buffer, DATA_BUFSIZE, "OK"); //SendBytes = DATA_BUFSIZE; Flags = 0; iRet = WSASend(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &SendBytes, Flags, &(PerIoData->Overlapped), NULL); if (iRet == SOCKET_ERROR) { if (WSAGetLastError() != WSA_IO_PENDING) { PostQueuedCompletionStatus(CompletionPort, -20, reinterpret_cast ((LPPER_HANDLE_DATA)&PerHandleData), (LPOVERLAPPED ) &PerIoData); } } printf("%d bytes data is sent /n", SendBytes); } else if (PerIoData->OperationType == SEND_POSTED) { // Post another WSASend or WSARecv operation. // As an example, we will post another WSARecv() // I/O operation. Flags = 0; // Set up the per-I/O operation data for the next // overlapped call ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.len = DATA_BUFSIZE; PerIoData->DataBuf.buf = PerIoData->Buffer; PerIoData->OperationType = RECV_POSTED; iRet = WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags, &(PerIoData->Overlapped), NULL); if (iRet == SOCKET_ERROR) { if (WSAGetLastError() != WSA_IO_PENDING) { PostQueuedCompletionStatus(CompletionPort, -10, reinterpret_cast((LPPER_HANDLE_DATA)&PerHandleData), (LPOVERLAPPED ) &PerIoData); } } } } } int _tmain() { SYSTEM_INFO stSysInfo; memset(&stSysInfo, 0, sizeof(stSysInfo)); SOCKADDR_IN InternetAddr; SOCKET Listen; DWORD RecvBytes; DWORD Flags = 0; // Load Winsock int iResult = StartWinsock(); if ( iResult == 0 ) { printf("winsock start up failed./n, error = %d/n", WSAGetLastError()); } // Create an I/O completion port // only processor's number thread is running by default. HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); // Determine how many processors are on the system GetSystemInfo(&stSysInfo); unsigned int i ; for(i = 0; i < stSysInfo.dwNumberOfProcessors; i++) { HANDLE ThreadHandle; // Create a server worker thread, and pass the // completion port to the thread. NOTE: the // ServerWorkerThread procedure is not defined // in this listing. ThreadHandle =(HANDLE) _beginthreadex(NULL, 0, ServerWorkerThread, hCompletionPort, 0, NULL); // Close the thread handle CloseHandle(ThreadHandle); } // Create a listening socket Listen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); int on = 1; setsockopt(Listen, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); InternetAddr.sin_family = AF_INET; InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY); InternetAddr.sin_port = htons(5150); bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)); // Prepare socket for listening listen(Listen, 5); while(1) { PER_HANDLE_DATA *PerHandleData=NULL; PER_IO_DATA *PerIoData = NULL; SOCKADDR_IN saRemote; SOCKET Accept; int RemoteLen; // Step 5: // Accept connections and assign to the completion // port RemoteLen = sizeof(saRemote); Accept = WSAAccept(Listen, (SOCKADDR *)&saRemote, &RemoteLen, NULL, NULL); // Step 6: // Create per-handle data information structure to // associate with the socket PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA)); PerIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA)); printf("Socket number %d connected/n", Accept); PerHandleData->Socket = Accept; memcpy(&PerHandleData->ClientAddr, &saRemote, RemoteLen); // Step 7: // Associate the accepted socket with the // completion port CreateIoCompletionPort((HANDLE) Accept, hCompletionPort, reinterpret_cast(PerHandleData), 0); // Set up the per-I/O operation data for the next // overlapped call ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED)); PerIoData->DataBuf.len = DATA_BUFSIZE; PerIoData->DataBuf.buf = PerIoData->Buffer; PerIoData->OperationType = RECV_POSTED; 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 0; } } } return 0; }
客户端代码:
// ClientTest.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include #include #pragma comment(lib, "ws2_32") #define BUFSIZE 10 int StartWinsock( ) { WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 2 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ printf("error = %d/n", WSAGetLastError()); return 0; } /* Confirm that the WinSock DLL supports 2.2.*/ /* Note that if the DLL supports versions greater */ /* than 2.2 in addition to 2.2, it will still return */ /* 2.2 in wVersion since that is the version we */ /* requested. */ if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 2 ) { /* Tell the user that we could not find a usable */ /* WinSock DLL. */ WSACleanup( ); return 0; } printf("max socket is :%d/n", wsaData.iMaxSockets); return 1; } int count = 0; unsigned __stdcall WorkerThread(LPVOID pSock) { SOCKET clientSock = reinterpret_cast(pSock); int iResult = 0; char buf[BUFSIZE]; int i = 0; while ( i < 10 ) { ZeroMemory(buf, BUFSIZE); memset(buf, 'E', BUFSIZE -1); //strcpy_s(buf, BUFSIZE, "1234567890"); iResult = send(clientSock, buf, BUFSIZE, 0); if ( iResult == SOCKET_ERROR ) { printf("%d个客户 send error = %d/n",count, WSAGetLastError()); } ZeroMemory(buf, BUFSIZE); iResult = recv(clientSock, buf, BUFSIZE, 0); if ( iResult == SOCKET_ERROR ) { printf("%d个客户 recv error = %d/n", count, WSAGetLastError()); continue; } printf("received data is :%s/n", buf); i++; Sleep(2000); } iResult = shutdown(clientSock, SD_BOTH); if ( SOCKET_ERROR == iResult ) { printf("%d个客户 shutdown error = %d/n", count, WSAGetLastError()); } iResult = closesocket(clientSock); if ( SOCKET_ERROR == iResult ) { printf("%d个客户 closesocket error = %d/n", count, WSAGetLastError()); } return 0; } int _tmain(int argc, _TCHAR* argv[]) { int iResult = StartWinsock(); struct sockaddr_in serverAddr; memset(&serverAddr, 0 ,sizeof(serverAddr)); serverAddr.sin_family = AF_INET; serverAddr.sin_port = htons(5150); serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); while (1) { count++; printf("第%d个socket连接",count); SOCKET clientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if ( clientSock ==INVALID_SOCKET ) { printf("socket error = %d/n", WSAGetLastError()); } iResult = connect(clientSock, (const sockaddr *)&serverAddr, sizeof(serverAddr)); if ( iResult == SOCKET_ERROR ) { printf("connect error = %d/n",WSAGetLastError()); closesocket(clientSock); continue; } _beginthreadex(NULL, 0, WorkerThread, (LPVOID)clientSock, 0, NULL); Sleep(5000); } WSACleanup(); return 0; }
可能存在一些资源未清理的情况,仅仅是做一个练习。