天天看點

IO完成端口學習示例

連接配接:

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;

}

可能存在一些資源未清理的情況,僅僅是做一個練習。

繼續閱讀