18,356
社区成员
发帖
与我相关
我的任务
分享
#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;
}