串連:
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 : 定義控制台應用程式的進入點。<br />//<br />#include "stdafx.h"<br />#include <WinSock2.h><br />#include <windows.h><br />#include <process.h><br />#pragma comment(lib, "ws2_32")<br />#define DATA_BUFSIZE 10<br />#define RECV_POSTED 0<br />#define SEND_POSTED 1<br />typedef struct _PER_HANDLE_DATA<br />{<br />SOCKETSocket;<br />SOCKADDR_STORAGE ClientAddr;<br />// Other information useful to be associated with the handle<br />} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;<br />typedef struct<br />{<br />OVERLAPPED Overlapped;<br />WSABUF DataBuf;<br />char Buffer[DATA_BUFSIZE];<br />int BufferLen;<br />int OperationType;<br />} PER_IO_DATA, *LPPER_IO_DATA;<br />int StartWinsock( )<br />{<br />WORD wVersionRequested;<br />WSADATA wsaData;<br />int err;<br />wVersionRequested = MAKEWORD( 2, 2 );<br />err = WSAStartup( wVersionRequested, &wsaData );<br />if ( err != 0 ) {<br />/* Tell the user that we could not find a usable */<br />/* WinSock DLL. */<br />printf("error = %d/n", WSAGetLastError());<br />return 0;<br />}<br />/* Confirm that the WinSock DLL supports 2.2.*/<br />/* Note that if the DLL supports versions greater */<br />/* than 2.2 in addition to 2.2, it will still return */<br />/* 2.2 in wVersion since that is the version we */<br />/* requested. */<br />if ( LOBYTE( wsaData.wVersion ) != 2 ||<br />HIBYTE( wsaData.wVersion ) != 2 ) {<br />/* Tell the user that we could not find a usable */<br />/* WinSock DLL. */<br />WSACleanup( );<br />return 0;<br />}<br />printf("max socket is :%d/n", wsaData.iMaxSockets);<br />return 1;<br />}<br />unsigned int WINAPI __stdcall ServerWorkerThread(LPVOID CompletionPortID)<br />{<br />// The requirements for the worker thread will be<br />// discussed later.<br />HANDLE CompletionPort = (HANDLE) CompletionPortID;<br />DWORD BytesTransferred;<br />LPPER_HANDLE_DATA PerHandleData;<br />LPPER_IO_DATA PerIoData;<br />DWORD SendBytes, RecvBytes;<br />DWORD Flags;<br />int iRet = 0;<br />while(1)<br />{<br />// Wait for I/O to complete on any socket<br />// associated with the completion port<br />iRet = GetQueuedCompletionStatus(CompletionPort,<br />&BytesTransferred,(LPDWORD)&PerHandleData,<br />(LPOVERLAPPED *) &PerIoData, INFINITE);<br />// First check to see if an error has occurred<br />// on the socket; if so, close the<br />// socket and clean up the per-handle data<br />// and per-I/O operation data associated with<br />// the socket<br />if ( BytesTransferred == 0 &&<br />(PerIoData->OperationType == RECV_POSTED || PerIoData->OperationType == SEND_POSTED) )<br />{<br />// A zero BytesTransferred indicates that the<br />// socket has been closed by the peer, so<br />// you should close the socket. Note:<br />// Per-handle data was used to reference the<br />// socket associated with the I/O operation.<br />closesocket(PerHandleData->Socket);<br />GlobalFree(PerHandleData);<br />GlobalFree(PerIoData);<br />continue;<br />}<br />if (iRet == 0)<br />{<br />closesocket(PerHandleData->Socket);<br />GlobalFree(PerHandleData);<br />GlobalFree(PerIoData);<br />continue;<br />}<br />if (BytesTransferred == -10)<br />{<br />// A zero BytesTransferred indicates that the<br />// socket has been closed by the peer, so<br />// you should close the socket. Note:<br />// Per-handle data was used to reference the<br />// socket associated with the I/O operation.<br />closesocket(PerHandleData->Socket);<br />GlobalFree(PerHandleData);<br />GlobalFree(PerIoData);<br />continue;<br />}<br />// Service the completed I/O request. You can<br />// determine which I/O request has just<br />// completed by looking at the OperationType<br />// field contained in the per-I/O operation data.<br />if (PerIoData->OperationType == RECV_POSTED)<br />{<br />// Do something with the received data<br />// in PerIoData->Buffer<br />printf("%s/n",PerIoData->Buffer);</p><p>//Response:<br />// Set up the per-I/O operation data for the next<br />// overlapped call<br />ZeroMemory(&(PerIoData->Overlapped),<br />sizeof(OVERLAPPED));</p><p>PerIoData->DataBuf.len = DATA_BUFSIZE;<br />PerIoData->DataBuf.buf = PerIoData->Buffer;<br />PerIoData->OperationType = SEND_POSTED;<br />memset(PerIoData->Buffer, 0, DATA_BUFSIZE);<br />strcpy_s(PerIoData->Buffer, DATA_BUFSIZE, "OK");<br />//SendBytes = DATA_BUFSIZE;<br />Flags = 0;<br />iRet = WSASend(PerHandleData->Socket,<br />&(PerIoData->DataBuf), 1, &SendBytes,<br />Flags, &(PerIoData->Overlapped), NULL);<br />if (iRet == SOCKET_ERROR)<br />{<br />if (WSAGetLastError() != WSA_IO_PENDING)<br />{<br />PostQueuedCompletionStatus(CompletionPort, -20, reinterpret_cast<DWORD> ((LPPER_HANDLE_DATA)&PerHandleData),<br />(LPOVERLAPPED ) &PerIoData);<br />}<br />}<br />printf("%d bytes data is sent /n", SendBytes);<br />}<br />else if (PerIoData->OperationType == SEND_POSTED)<br />{<br />// Post another WSASend or WSARecv operation.<br />// As an example, we will post another WSARecv()<br />// I/O operation.<br />Flags = 0;<br />// Set up the per-I/O operation data for the next<br />// overlapped call<br />ZeroMemory(&(PerIoData->Overlapped),<br />sizeof(OVERLAPPED));<br />PerIoData->DataBuf.len = DATA_BUFSIZE;<br />PerIoData->DataBuf.buf = PerIoData->Buffer;<br />PerIoData->OperationType = RECV_POSTED;<br />iRet = WSARecv(PerHandleData->Socket,<br />&(PerIoData->DataBuf), 1, &RecvBytes,<br />&Flags, &(PerIoData->Overlapped), NULL);<br />if (iRet == SOCKET_ERROR)<br />{<br />if (WSAGetLastError() != WSA_IO_PENDING)<br />{<br />PostQueuedCompletionStatus(CompletionPort, -10, reinterpret_cast<DWORD>((LPPER_HANDLE_DATA)&PerHandleData),<br />(LPOVERLAPPED ) &PerIoData);<br />}<br />}<br />}<br />}<br />}<br />int _tmain()<br />{<br />SYSTEM_INFO stSysInfo;<br />memset(&stSysInfo, 0, sizeof(stSysInfo));<br />SOCKADDR_IN InternetAddr;<br />SOCKET Listen;<br />DWORD RecvBytes;<br />DWORD Flags = 0;<br />// Load Winsock<br />int iResult = StartWinsock();<br />if ( iResult == 0 )<br />{<br />printf("winsock start up failed./n, error = %d/n", WSAGetLastError());<br />}<br />// Create an I/O completion port<br />// only processor's number thread is running by default.<br />HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);<br />// Determine how many processors are on the system<br />GetSystemInfo(&stSysInfo);<br />unsigned int i ;<br />for(i = 0; i < stSysInfo.dwNumberOfProcessors; i++)<br />{<br />HANDLE ThreadHandle;<br />// Create a server worker thread, and pass the<br />// completion port to the thread. NOTE: the<br />// ServerWorkerThread procedure is not defined<br />// in this listing.<br />ThreadHandle =(HANDLE) _beginthreadex(NULL, 0, ServerWorkerThread, hCompletionPort, 0, NULL);</p><p>// Close the thread handle<br />CloseHandle(ThreadHandle);<br />}<br />// Create a listening socket<br />Listen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0,<br />WSA_FLAG_OVERLAPPED);<br />int on = 1;<br />setsockopt(Listen, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));<br />InternetAddr.sin_family = AF_INET;<br />InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);<br />InternetAddr.sin_port = htons(5150);<br />bind(Listen, (PSOCKADDR) &InternetAddr,<br />sizeof(InternetAddr));<br />// Prepare socket for listening<br />listen(Listen, 5);<br />while(1)<br />{<br />PER_HANDLE_DATA *PerHandleData=NULL;<br />PER_IO_DATA *PerIoData = NULL;<br />SOCKADDR_IN saRemote;<br />SOCKET Accept;<br />int RemoteLen;<br />// Step 5:<br />// Accept connections and assign to the completion<br />// port<br />RemoteLen = sizeof(saRemote);<br />Accept = WSAAccept(Listen, (SOCKADDR *)&saRemote,<br />&RemoteLen, NULL, NULL);<br />// Step 6:<br />// Create per-handle data information structure to<br />// associate with the socket<br />PerHandleData = (LPPER_HANDLE_DATA)<br />GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));<br />PerIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA));<br />printf("Socket number %d connected/n", Accept);<br />PerHandleData->Socket = Accept;<br />memcpy(&PerHandleData->ClientAddr, &saRemote, RemoteLen);<br />// Step 7:<br />// Associate the accepted socket with the<br />// completion port<br />CreateIoCompletionPort((HANDLE) Accept,<br />hCompletionPort, reinterpret_cast<DWORD>(PerHandleData), 0);<br />// Set up the per-I/O operation data for the next<br />// overlapped call<br />ZeroMemory(&(PerIoData->Overlapped),<br />sizeof(OVERLAPPED));<br />PerIoData->DataBuf.len = DATA_BUFSIZE;<br />PerIoData->DataBuf.buf = PerIoData->Buffer;<br />PerIoData->OperationType = RECV_POSTED;<br />if (WSARecv(Accept, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,<br />&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)<br />{<br />if (WSAGetLastError() != ERROR_IO_PENDING)<br />{<br />printf("WSARecv() failed with error %d/n", WSAGetLastError());<br />return 0;<br />}<br />}<br />}<br />return 0;<br />}<br />
用戶端代碼:
// ClientTest.cpp : 定義控制台應用程式的進入點。<br />//<br />#include "stdafx.h"<br />#include <winsock2.h><br />#include <process.h><br />#pragma comment(lib, "ws2_32")<br />#define BUFSIZE10<br />int StartWinsock( )<br />{<br />WORD wVersionRequested;<br />WSADATA wsaData;<br />int err;<br />wVersionRequested = MAKEWORD( 2, 2 );<br />err = WSAStartup( wVersionRequested, &wsaData );<br />if ( err != 0 ) {<br />/* Tell the user that we could not find a usable */<br />/* WinSock DLL. */<br />printf("error = %d/n", WSAGetLastError());<br />return 0;<br />}<br />/* Confirm that the WinSock DLL supports 2.2.*/<br />/* Note that if the DLL supports versions greater */<br />/* than 2.2 in addition to 2.2, it will still return */<br />/* 2.2 in wVersion since that is the version we */<br />/* requested. */<br />if ( LOBYTE( wsaData.wVersion ) != 2 ||<br />HIBYTE( wsaData.wVersion ) != 2 ) {<br />/* Tell the user that we could not find a usable */<br />/* WinSock DLL. */<br />WSACleanup( );<br />return 0;<br />}<br />printf("max socket is :%d/n", wsaData.iMaxSockets);<br />return 1;<br />}<br />int count = 0;<br />unsigned __stdcall WorkerThread(LPVOID pSock)<br />{<br />SOCKET clientSock = reinterpret_cast<SOCKET>(pSock);<br />int iResult = 0;<br />char buf[BUFSIZE];<br />int i = 0;<br />while ( i < 10 )<br />{<br />ZeroMemory(buf, BUFSIZE);<br />memset(buf, 'E', BUFSIZE -1);<br />//strcpy_s(buf, BUFSIZE, "1234567890");<br />iResult = send(clientSock, buf, BUFSIZE, 0);<br />if ( iResult == SOCKET_ERROR )<br />{<br />printf("%d個客戶 send error = %d/n",count, WSAGetLastError());<br />}<br />ZeroMemory(buf, BUFSIZE);<br />iResult = recv(clientSock, buf, BUFSIZE, 0);<br />if ( iResult == SOCKET_ERROR )<br />{<br />printf("%d個客戶 recv error = %d/n", count, WSAGetLastError());<br />continue;<br />}<br />printf("received data is :%s/n", buf);<br />i++;<br />Sleep(2000);<br />}<br />iResult = shutdown(clientSock, SD_BOTH);<br />if ( SOCKET_ERROR == iResult )<br />{<br />printf("%d個客戶 shutdown error = %d/n", count, WSAGetLastError());<br />}<br />iResult = closesocket(clientSock);<br />if ( SOCKET_ERROR == iResult )<br />{<br />printf("%d個客戶 closesocket error = %d/n", count, WSAGetLastError());<br />}<br />return 0;<br />}<br />int _tmain(int argc, _TCHAR* argv[])<br />{<br />int iResult = StartWinsock();<br />struct sockaddr_in serverAddr;<br />memset(&serverAddr, 0 ,sizeof(serverAddr));<br />serverAddr.sin_family = AF_INET;<br />serverAddr.sin_port = htons(5150);<br />serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");<br />while (1)<br />{<br />count++;<br />printf("第%d個socket串連",count);<br />SOCKET clientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);<br />if ( clientSock ==INVALID_SOCKET )<br />{<br />printf("socket error = %d/n", WSAGetLastError());<br />}<br />iResult = connect(clientSock, (const sockaddr *)&serverAddr, sizeof(serverAddr));<br />if ( iResult == SOCKET_ERROR )<br />{<br />printf("connect error = %d/n",WSAGetLastError());<br />closesocket(clientSock);<br />continue;<br />}<br />_beginthreadex(NULL, 0, WorkerThread, (LPVOID)clientSock, 0, NULL);</p><p>Sleep(5000);<br />}<br />WSACleanup();<br />return 0;<br />}<br />
可能存在一些資源未清理的情況,僅僅是做一個練習。