#include <winsock2.h>
//#include <windows.h>
#include <stdio.h>
#define PORT 5150
#define DATA_BUFSIZE 8192
typedef struct
{
OVERLAPPED Overlapped;
WSABUF DataBuf;
CHAR Buffer[DATA_BUFSIZE];
DWORD BytesSEND;
DWORD BytesRECV;
} PER_IO_OPERATION_DATA, * LPPER_IO_OPERATION_DATA;
typedef struct
{
SOCKET Socket;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;
DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID);
int main(void)
{
SOCKADDR_IN InternetAddr;
SOCKET Listen;
SOCKET Accept;
HANDLE CompletionPort;
SYSTEM_INFO SystemInfo;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
int i;
DWORD RecvBytes;
DWORD Flags;
DWORD ThreadID;
WSADATA wsaData;
DWORD Ret;
if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
{
printf("WSAStartup失敗了,錯(cuò)誤信息如下: %d\n", Ret);
return;
}
// 設(shè)置一個(gè)I/O完成端口.
if ((CompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL)
{
printf( "CreateIoCompletionPort 失敗了,錯(cuò)誤信息如下: %d\n", GetLastError());
return;
}
// 測(cè)試系統(tǒng)中有多少cpu處理器
GetSystemInfo(&SystemInfo);
// 基于系統(tǒng)可用的處理器創(chuàng)建工作線程,為每個(gè)處理器創(chuàng)建連個(gè)線程
for(i = 0; i < SystemInfo.dwNumberOfProcessors * 2; i++)
{
HANDLE ThreadHandle;
// 創(chuàng)建一個(gè)服務(wù)端線程并且傳遞一個(gè)完成端口給這個(gè)線程.
if ((ThreadHandle = CreateThread(NULL, 0, ServerWorkerThread, CompletionPort,
0, &ThreadID)) == NULL)
{
printf("CreateThread()發(fā)生了如下錯(cuò)誤: %d\n", GetLastError());
return;
}
else
{printf("創(chuàng)建了一個(gè)完成端口.\n");
}
// 關(guān)閉 thread句柄
CloseHandle(ThreadHandle);
}
// 創(chuàng)建一個(gè)監(jiān)聽(tīng)套接字
if ((Listen =WSASocket(AF_INET, SOCK_STREAM, 0, NULL,0,WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
printf("WSASocket() 發(fā)生了如下錯(cuò)誤: %d\n", WSAGetLastError());
return;
}
else
{printf("創(chuàng)建監(jiān)聽(tīng)套接字成功\n");}
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY);
InternetAddr.sin_port = htons(PORT);
if (bind(Listen, (PSOCKADDR) &InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
{
printf("bind()端口或IP時(shí)發(fā)生了如下錯(cuò)誤: %d\n", WSAGetLastError());
return;
}
else
{printf("綁定端口%d成功\n",PORT);}
// 準(zhǔn)備socket 用來(lái)監(jiān)聽(tīng)
if (listen(Listen, 5) == SOCKET_ERROR)
{
printf("listen() 發(fā)生了如下錯(cuò)誤 %d\n", WSAGetLastError());
return;
}
else
{printf("預(yù)處理成功,開(kāi)始在端口 %d 處監(jiān)聽(tīng)...\n",PORT);}
//接受連接并且交給完成端口處理
while(TRUE)
{
if ((Accept = WSAAccept(Listen, NULL, NULL, NULL, 0)) == SOCKET_ERROR)
{
printf("WSAAccept() 發(fā)生了如下錯(cuò)誤: %d\n", WSAGetLastError());
return;
}
// 創(chuàng)建一個(gè)套接字信息結(jié)構(gòu)體去聯(lián)系起來(lái)socket
if ((PerHandleData = (LPPER_HANDLE_DATA) GlobalAlloc(GPTR,
sizeof(PER_HANDLE_DATA))) == NULL)
{
printf("GlobalAlloc() 發(fā)生了如下錯(cuò)誤: %d\n", GetLastError());
return;
}
// 將接受到的套接字與原始的完成端口聯(lián)系起來(lái).
printf("號(hào)碼為 %d 的socket連接上了\n", Accept);
PerHandleData->Socket = Accept;
if (CreateIoCompletionPort((HANDLE) Accept, CompletionPort, (DWORD) PerHandleData,
0) == NULL)
{
printf("CreateIoCompletionPort 發(fā)生了如下錯(cuò)誤: %d\n", GetLastError());
return;
}
// 創(chuàng)建每一個(gè)I/O 套接字信息結(jié)構(gòu)體去和下面被調(diào)用的 to associate with the
// WSARecv 連接.
if ((PerIoData = (LPPER_IO_OPERATION_DATA) GlobalAlloc(GPTR, sizeof(PER_IO_OPERATION_DATA))) == NULL)
{
printf("GlobalAlloc() 發(fā)生了如下錯(cuò)誤: %d\n", GetLastError());
return;
}
else{printf("接收了一個(gè)連接\n");}
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->BytesSEND = 0;
PerIoData->BytesRECV = 0;
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
Flags = 0;
if (WSARecv(Accept, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() 發(fā)生了如下錯(cuò)誤: %d\n", WSAGetLastError());
return;
}
}
}
}
DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
HANDLE CompletionPort = (HANDLE) CompletionPortID;
DWORD BytesTransferred;
LPOVERLAPPED Overlapped;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD SendBytes, RecvBytes;
DWORD Flags;
while(TRUE)
{
if (GetQueuedCompletionStatus(CompletionPort, &BytesTransferred,
(LPDWORD)&PerHandleData, (LPOVERLAPPED *) &PerIoData, INFINITE) == 0)
{
printf("GetQueuedCompletionStatus 發(fā)生了如下錯(cuò)誤: %d\n", GetLastError());
return 0;
}
//首先檢查一下去套接字看是否在上發(fā)生了錯(cuò)誤并且如果發(fā)生了錯(cuò)誤就關(guān)閉套接
//字并且清除與套接字連接的 SOCKET_INFORMATION結(jié)構(gòu)信息體
if (BytesTransferred == 0)
{
printf("正在關(guān)閉socket %d\n", PerHandleData->Socket);
if (closesocket(PerHandleData->Socket) == SOCKET_ERROR)
{
printf("closesocket() 發(fā)生了如下錯(cuò)誤: %d\n", WSAGetLastError());
return 0;
}
GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}
//檢查如果 BytesRECV字段等于0,這就意味著一個(gè) WSARecv調(diào)用剛剛完成了所以從完成的WSARecv()調(diào)用中
//用BytesTransferred值更新 BytesRECV字段
if (PerIoData->BytesRECV == 0)
{
PerIoData->BytesRECV = BytesTransferred;
PerIoData->BytesSEND = 0;
}
else
{
PerIoData->BytesSEND += BytesTransferred;
}
if (PerIoData->BytesRECV > PerIoData->BytesSEND)
{
//發(fā)布另外一個(gè) WSASend()請(qǐng)求
//既然WSASend()不是 gauranteed去發(fā)送所有字節(jié)的請(qǐng)求
//繼續(xù)調(diào)用 WSASend()發(fā)送直到所有收到的字節(jié)被發(fā)送
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->DataBuf.buf = PerIoData->Buffer + PerIoData->BytesSEND;
PerIoData->DataBuf.len = PerIoData->BytesRECV - PerIoData->BytesSEND;
if (WSASend(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &SendBytes, 0,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSASend() 發(fā)生了如下錯(cuò)誤: %d\n", WSAGetLastError());
return 0;
}
}
}
else
{
PerIoData->BytesRECV = 0;
//現(xiàn)在沒(méi)有更多的字節(jié)發(fā)送過(guò)去用來(lái)post另外一個(gè)WSARecv()請(qǐng)求
Flags = 0;
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->DataBuf.len = DATA_BUFSIZE;
PerIoData->DataBuf.buf = PerIoData->Buffer;
if (WSARecv(PerHandleData->Socket, &(PerIoData->DataBuf), 1, &RecvBytes, &Flags,
&(PerIoData->Overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() 發(fā)生了如下錯(cuò)誤: %d\n", WSAGetLastError());
return 0;
}
}
}
}
}
posted on 2010-02-24 13:34
暗夜教父 閱讀(938)
評(píng)論(0) 編輯 收藏 引用 所屬分類:
C & C++