連接配接:
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 <WinSock2.h>
#include <windows.h>
#include <process.h>
#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<DWORD> ((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<DWORD>((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<DWORD>(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 <winsock2.h>
#include <process.h>
#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<SOCKET>(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;
}
可能存在一些資源未清理的情況,僅僅是做一個練習。