IOCP收发/连接/接受连接全异步处理

xprotect 2011-12-31 01:07:21
只是一个示例,无实用价值

#include <winsock2.h>
#include <mswsock.h>
#include <iostream>

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

using namespace std;

void StartServer();
void StartClient();

int main(int argc, char** argv)
{
WSAData wsaData;
WSAStartup(MAKEWORD(1, 1), &wsaData);

if (argc > 1)
StartServer();
else
StartClient();

cin.get();
return 0;
}

//////////////////////////////////////////////////////////////////////////
// server

#define SEND 0
#define RECV 1
#define ACCEPT 2
#define CONNECT 3

#define DATA_LENGTH 1024

typedef struct _PER_HANDLE_DATA
{
SOCKET socket;
SOCKADDR_STORAGE clientAddr;
}PER_HANDLE_DATA,*LPPER_HANDLE_DATA;

typedef struct{
OVERLAPPED overlapped;
WSABUF buffer;
char dataBuffer[DATA_LENGTH];
int dataLength;
int operatorType;
SOCKET client;
}PER_IO_DATA,*LPPER_IO_DATA;

LPFN_ACCEPTEX lpfnAcceptEx = NULL;
unsigned WINAPI ServerThread(LPVOID lpParam);

void StartServer()
{
HANDLE CompletionPort;
SOCKADDR_IN addr;

CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

SOCKET Listen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
LPPER_HANDLE_DATA perDandleData;
perDandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));
perDandleData->socket = Listen;
CreateIoCompletionPort((HANDLE)Listen, CompletionPort, (ULONG_PTR)perDandleData, 0);

addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(1234);

bind(Listen, (PSOCKADDR)&addr, sizeof(addr));
listen(Listen,5);

GUID guidAcceptEx = WSAID_ACCEPTEX;
DWORD dwBytes = 0;
if (!WSAIoctl(Listen, SIO_GET_EXTENSION_FUNCTION_POINTER,
&guidAcceptEx, sizeof(guidAcceptEx), &lpfnAcceptEx, sizeof(lpfnAcceptEx),
&dwBytes, NULL, NULL) == 0)
{
cout<<"WSAIoctl failed..."<<endl;
return;
}

LPPER_IO_DATA perIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
memset(&(perIoData->overlapped),0,sizeof(OVERLAPPED));
perIoData->operatorType = ACCEPT;
perIoData->client = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

cout<<"Process AcceptEx function wait for client connect..."<<endl;
BOOL bRet = lpfnAcceptEx(Listen, perIoData->client, perIoData->dataBuffer, 0,
sizeof(SOCKADDR_IN)+16, sizeof(SOCKADDR_IN)+16, &dwBytes,
&(perIoData->overlapped));
if (bRet == FALSE)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
cout<<"lpfnAcceptEx failed.."<<endl;
}

// only one thread for test
ServerThread(CompletionPort);
}

unsigned WINAPI ServerThread(LPVOID lpParam)
{
HANDLE CompletionPort = (HANDLE)lpParam;
DWORD bytes;
LPPER_HANDLE_DATA perHandleData = NULL;
LPPER_IO_DATA perIoData;
DWORD Flags;
int ret;
DWORD RecvBytes;

while(true)
{
bytes = -1;
ret = GetQueuedCompletionStatus(
CompletionPort,
&bytes,
(LPDWORD)&perHandleData,
(LPOVERLAPPED*)&perIoData,
INFINITE);

if (bytes == 0 && (perIoData->operatorType == RECV ||
perIoData->operatorType == SEND))
{
closesocket(perHandleData->socket);
GlobalFree(perHandleData);
GlobalFree(perIoData);
cout<<"closesocket and globalfree perhandledata periodata!"<<endl;
continue;
}

if (perIoData->operatorType == ACCEPT)
{
// new accept
LPPER_IO_DATA newPerIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
memset(&(newPerIoData->overlapped), 0, sizeof(OVERLAPPED));
newPerIoData->operatorType = ACCEPT;
newPerIoData->client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
DWORD flags = 0;

DWORD dwBytes = 0;
cout<<"Process AcceptEx function wait for client connect..."<<endl;
int rc = lpfnAcceptEx(perHandleData->socket, newPerIoData->client,
newPerIoData->dataBuffer, 0,
sizeof(SOCKADDR_IN)+16, sizeof(SOCKADDR_IN)+16, &dwBytes,
&(newPerIoData->overlapped));
if (rc == FALSE)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
cout<<"lpfnAcceptEx failed.." <<WSAGetLastError()<<endl;
}

// begin receive data
if (setsockopt(perIoData->client, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
(char*)&(perHandleData->socket), sizeof(perHandleData->socket)) == SOCKET_ERROR)
{
cout<<"setsockopt..."<<endl;
}

LPPER_HANDLE_DATA newPerDandleData;
newPerDandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));
newPerDandleData->socket = perIoData->client;

CreateIoCompletionPort((HANDLE)newPerDandleData->socket,
CompletionPort, (ULONG_PTR)newPerDandleData, 0);

memset(&(perIoData->overlapped), 0, sizeof(OVERLAPPED));
perIoData->operatorType = RECV;
perIoData->buffer.buf = perIoData->dataBuffer;
perIoData->buffer.len = perIoData->dataLength = DATA_LENGTH-1;

cout<<"wait for data arrive(Accept)..."<<endl;
Flags = 0;
if (WSARecv(newPerDandleData->socket, &(perIoData->buffer), 1,
&RecvBytes, &Flags, &(perIoData->overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() == WSA_IO_PENDING)
cout<<"WSARecv Pending..."<<endl;
}

continue;
}
else if (perIoData->operatorType == RECV)
{
perIoData->buffer.buf[bytes] = 0;
cout<<perIoData->buffer.buf << endl;
send(perHandleData->socket, perIoData->buffer.buf, bytes, 0);
}
Flags = 0;
perIoData->operatorType = RECV;

ZeroMemory(&(perIoData->overlapped), sizeof(OVERLAPPED));
WSARecv(perHandleData->socket, &(perIoData->buffer), 1,
&RecvBytes, &Flags, &(perIoData->overlapped), NULL);
}

return 0;
}

//////////////////////////////////////////////////////////////////////////
// client

LPFN_CONNECTEX lpfnConnectEx = NULL;
unsigned WINAPI ClientThread(LPVOID lpParam);

void StartClient()
{
HANDLE CompletionPort;
SOCKADDR_IN addr;

CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

SOCKET Client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
LPPER_HANDLE_DATA perDandleData;
perDandleData = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));
perDandleData->socket = Client;
CreateIoCompletionPort((HANDLE)Client, CompletionPort, (ULONG_PTR)perDandleData, 0);

addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(0);

bind(Client, (PSOCKADDR)&addr, sizeof(addr));

GUID guidAcceptEx = WSAID_CONNECTEX;
DWORD dwBytes = 0;
if (!WSAIoctl(Client, SIO_GET_EXTENSION_FUNCTION_POINTER,
&guidAcceptEx, sizeof(guidAcceptEx), &lpfnConnectEx, sizeof(lpfnConnectEx),
&dwBytes, NULL, NULL) == 0)
{
cout<<"WSAIoctl failed..."<<endl;
return;
}

LPPER_IO_DATA perIoData = (LPPER_IO_DATA)GlobalAlloc(GPTR, sizeof(PER_IO_DATA));
memset(&(perIoData->overlapped),0,sizeof(OVERLAPPED));
perIoData->operatorType = CONNECT;

addr.sin_family = AF_INET;
addr.sin_addr.s_addr=inet_addr("127.0.0.1");
addr.sin_port = htons(1234);

BOOL bRet = lpfnConnectEx(Client, (PSOCKADDR)&addr, sizeof(addr),
perIoData->dataBuffer, 0, &dwBytes, &(perIoData->overlapped));
if (bRet == FALSE)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
cout<<"lpfnConnectEx failed.."<<endl;
}

ClientThread(CompletionPort);
}

unsigned WINAPI ClientThread(LPVOID lpParam)
{
HANDLE CompletionPort = (HANDLE)lpParam;
DWORD bytes;
LPPER_HANDLE_DATA perHandleData = NULL;
LPPER_IO_DATA perIoData;
DWORD Flags;
int ret;
DWORD SendBytes;

while(true)
{
bytes = -1;
ret = GetQueuedCompletionStatus(
CompletionPort,
&bytes,
(LPDWORD)&perHandleData,
(LPOVERLAPPED*)&perIoData,
INFINITE);

if (bytes == 0 && (perIoData->operatorType == RECV ||
perIoData->operatorType == SEND))
{
closesocket(perHandleData->socket);
GlobalFree(perHandleData);
GlobalFree(perIoData);
cout<<"closesocket and globalfree perhandledata periodata!"<<endl;
continue;
}

if (perIoData->operatorType == CONNECT)
{
cout<<"connected..."<<endl;
memset(&(perIoData->overlapped), 0, sizeof(OVERLAPPED));
gets(perIoData->dataBuffer);
perIoData->operatorType = SEND;
perIoData->buffer.buf = perIoData->dataBuffer;
perIoData->buffer.len = (u_long)strlen(perIoData->dataBuffer);

if (WSASend(perHandleData->socket, &(perIoData->buffer), 1,
&SendBytes, 0, &(perIoData->overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() == WSA_IO_PENDING)
cout<<"WSARecv Pending..."<<endl;
}

continue;
}

gets(perIoData->dataBuffer);
perIoData->operatorType = SEND;
perIoData->buffer.buf = perIoData->dataBuffer;
perIoData->buffer.len = (u_long)strlen(perIoData->dataBuffer);
ZeroMemory(&(perIoData->overlapped), sizeof(OVERLAPPED));
Flags = 0;
if (WSASend(perHandleData->socket, &(perIoData->buffer), 1,
&SendBytes, Flags, &(perIoData->overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() == WSA_IO_PENDING)
cout<<"WSARecv Pending..."<<endl;
}
}

return 0;
}

...全文
98 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
xprotect 2012-01-17
  • 打赏
  • 举报
回复
这么有用的代码怎么没人看呢
Icer 2012-01-01
  • 打赏
  • 举报
回复
just just a sample
tubo_true 2011-12-31
  • 打赏
  • 举报
回复









18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧