您的位置:首页 > 移动开发

SOCKET编程进阶之Overlapped IO完成例程模型

2011-11-18 14:35 507 查看
SOCKET编程进阶之Overlapped IO完成例程模型

完成例程模型相比与事件通知模型有个很大的优点就是不再受64个消息的限制,一个线程可以同时管理成百上千个socket连接,且保持较高的性能。

完成例程相比与完成端口较为逊色,因为它的性能不能随着系统CPU数量的增长而线程增长,不过在我看来已经很强了,呵呵~!

说白了,这些连接都是由系统来帮你管理的。你只需做的一件事就是:开启一个线程来accept进来的连接,剩下的工作交由系统来处理。而你,则需要提供给系统一个回调函数,发生新的网络事件的时候系统将执行这个函数:

procedure WorkerRoutine( const dwError, cbTransferred : DWORD; const lpOverlapped : LPWSAOVERLAPPED; const dwFlags : DWORD ); stdcall;

然后告诉系统用WorkerRoutine函数处理接收到的数据:

WSARecv( m_socket, @FBuf, 1, dwTemp, dwFlag, @m_overlap, WorkerRoutine );

然后......没有什么然后了,系统什么都给你做了!

源码---------------------------------------------------------------------------------------------

#pragma comment(lib,"ws2_32.lib")

#include <winsock2.h>

#include <stdio.h>

#define DATA_BUFSIZE 1024 // 接收缓冲区大小

#define MAXSESSION 10000 // 最大连接数

typedef struct _SOCKET_INFORMATION {

OVERLAPPED Overlapped;

SOCKET Socket;

WSABUF DataBuf;

DWORD BytesSEND;

DWORD BytesRECV;

} SOCKET_INFORMATION, * LPSOCKET_INFORMATION;

SOCKET ListenSocket = INVALID_SOCKET;

DWORD Flags = 0; // WSARecv的参数

void CALLBACK WorkerRoutine(DWORD Error, DWORD BytesTransferred,LPWSAOVERLAPPED Overlapped, DWORD InFlags);

DWORD WINAPI AcceptThread(LPVOID lpParameter)

{

WSADATA wsaData;

WSAStartup(MAKEWORD(2,2),&wsaData);

ListenSocket = WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,NULL,WSA_FLAG_OVERLAPPED);

SOCKADDR_IN ServerAddr;

ServerAddr.sin_family = AF_INET;

ServerAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);

ServerAddr.sin_port = htons(1234);

bind(ListenSocket,(LPSOCKADDR)&ServerAddr,sizeof(ServerAddr));

listen(ListenSocket,100);

printf("listenning...\n");

SOCKADDR_IN ClientAddr;

int addr_length=sizeof(ClientAddr);

while (TRUE)

{

LPSOCKET_INFORMATION SI = new SOCKET_INFORMATION;

if ((SI->Socket = accept(ListenSocket,(SOCKADDR*)&ClientAddr, &addr_length)) != INVALID_SOCKET)

{

printf("accept ip:%s port:%d\n",inet_ntoa(ClientAddr.sin_addr),ClientAddr.sin_port);

memset(&SI->Overlapped,0,sizeof(WSAOVERLAPPED));

SI->DataBuf.buf = new char[DATA_BUFSIZE];

SI->DataBuf.len = DATA_BUFSIZE;

memset(SI->DataBuf.buf,0,DATA_BUFSIZE);

if(WSARecv(SI->Socket, &SI->DataBuf, 1, &SI->BytesRECV, &Flags, &SI->Overlapped, WorkerRoutine) == SOCKET_ERROR)

{

int err = WSAGetLastError();

if(WSAGetLastError() != WSA_IO_PENDING)

{

printf("disconnect\n");

closesocket(SI->Socket);

delete [] SI->DataBuf.buf;

delete SI;

continue;

}

}

}

}

return FALSE;

}

void CALLBACK WorkerRoutine(DWORD Error, DWORD BytesTransferred, LPWSAOVERLAPPED Overlapped, DWORD InFlags)

{

LPSOCKET_INFORMATION SI = (LPSOCKET_INFORMATION)Overlapped;

if (Error != 0 || BytesTransferred == 0)

{

printf("disconnect\n");

closesocket(SI->Socket);

delete [] SI->DataBuf.buf;

delete SI;

return;

}

//使用数据

printf("call back:%s\n",SI->DataBuf.buf);

memset(SI->DataBuf.buf,0,DATA_BUFSIZE);

if(WSARecv(SI->Socket, &SI->DataBuf, 1, &SI->BytesRECV, &Flags, &SI->Overlapped, WorkerRoutine) == SOCKET_ERROR)

{

int err = WSAGetLastError();

if(WSAGetLastError() != WSA_IO_PENDING)

{

printf("disconnect\n");

closesocket(SI->Socket);

delete [] SI->DataBuf.buf;

delete SI;

return;

}

}

}

void main()

{

HANDLE hThreads = CreateThread(NULL, 0, AcceptThread, NULL, NULL, NULL);

WaitForSingleObject(hThreads,INFINITE);

printf("exit\n");

CloseHandle(hThreads);

}

唉~花了好长时间才搞定了Overlapped I\O ,不过这还不是winsock编程的最高境界;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: