// test.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
// winsock 2 的头文件和库
#include <winsock2.h>
#include <MSWSock.h>
#include <iostream>
#include <list>
#include <windows.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
enum IOOperType{
TYPE_RECV, //数据接收事件
TYPE_SEND, //数据发送事件
};
struct IO_DATA
{
OVERLAPPED overLapped;
WSABUF wsabuf;
char buf[1024];
IOOperType operType;
SOCKET client;
void Init(IOOperType type,const SOCKET& sck,int len = 0)
{
memset(&overLapped, 0, sizeof(overLapped));
operType = type;
wsabuf.buf = buf;
memset(buf, 0, sizeof(buf));
if (0 == len)
{
wsabuf.len = sizeof(buf);
}
else
{
wsabuf.len = len;
}
client = sck;
}
};
list<IO_DATA*> g_listUnUseData;
list<IO_DATA*> g_listData;
CRITICAL_SECTION g_cs;
long g_nCount = 0;
IO_DATA* GetOverlapped()
{
EnterCriticalSection(&g_cs);
IO_DATA* pTmp = NULL;
if (g_listUnUseData.size()>0)
{
pTmp = g_listUnUseData.back();
g_listUnUseData.pop_back();
}
else
{
pTmp = new(IO_DATA);
g_listData.push_front(pTmp);
}
LeaveCriticalSection(&g_cs);
return pTmp;
}
void RecycleOverlapped(IO_DATA* pData)
{
EnterCriticalSection(&g_cs);
g_listUnUseData.push_front(pData);
LeaveCriticalSection(&g_cs);
}
DWORD _stdcall WorkerThread(LPVOID lParam)
{
HANDLE* pHandle = (HANDLE*)lParam;
IO_DATA* lpIOContext = NULL;
DWORD nBytes = 0;
DWORD dwFlags = 0;
int nRet = 0;
DWORD dwIoSize = 0;
void * lpCompletionKey = NULL;
LPOVERLAPPED lpOverlapped = NULL;
while (1)
{
GetQueuedCompletionStatus(*pHandle, &dwIoSize, (LPDWORD)&lpCompletionKey, &lpOverlapped, INFINITE);
lpIOContext = (IO_DATA*)lpOverlapped;
if (dwIoSize == 0)
{
cout << "Client disconnect" << endl;
closesocket(lpIOContext->client);
RecycleOverlapped(lpIOContext);
continue;
}
switch (lpIOContext->operType)
{
case TYPE_RECV:
{
InterlockedIncrement(&g_nCount);
if (0 == g_nCount % 100000)
cout << g_nCount << endl;
lpIOContext->Init(TYPE_RECV, lpIOContext->client);
DWORD nBytes = 1024, dwFlags = 0;
int nRet = WSARecv(lpIOContext->client, &lpIOContext->wsabuf, 1, &nBytes, &dwFlags, &lpIOContext->overLapped, NULL);
if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError())){
cout << "WASRecv Failed::Reason Code::" << WSAGetLastError() << endl;
closesocket(lpIOContext->client);
RecycleOverlapped(lpIOContext);
}
IO_DATA* pData = GetOverlapped();
pData->Init(TYPE_SEND, lpIOContext->client);
sprintf_s(pData->buf, "hello %s", lpIOContext->buf);
DWORD SendBytes = strlen(pData->buf);
pData->wsabuf.len = SendBytes;
nRet = WSASend(pData->client, &pData->wsabuf, 1,
&SendBytes, 0, &pData->overLapped, NULL);
if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError())){
cout << "WSASend Failed::Reason Code::" << WSAGetLastError() << endl;
closesocket(lpIOContext->client);
RecycleOverlapped(lpIOContext);
}
}
break;
case TYPE_SEND:
{
RecycleOverlapped(lpIOContext);
}
break;
default:
break;
}
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
InitializeCriticalSection(&g_cs);
//listen socket需要将accept操作投递到完成端口,因此,listen socket属性必须有重叠IO
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
SOCKET hSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (hSocket == INVALID_SOCKET)
{
cout << "WSASocket create socket error" << WSAGetLastError() << endl;
return false;
}
int nMaxConcurrency = 8;
HANDLE hHandleIocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, nMaxConcurrency);
//创建并设置IOCP并发线程数量
if (INVALID_HANDLE_VALUE == hHandleIocp)
{
cout << "IOCP create error,error code " << WSAGetLastError() << endl;
return false;
}
sockaddr_in service;
service.sin_family = AF_INET;
service.sin_port = htons(6666);
service.sin_addr.s_addr = inet_addr("127.0.0.1");
if (bind(hSocket, (sockaddr*)&service, sizeof(service)) == SOCKET_ERROR)
{
cout << "bind() error,error code " << WSAGetLastError() << endl;
return false;
}
cout << "bind ok!" << endl;
if (listen(hSocket, SOMAXCONN) == SOCKET_ERROR)
{
cout << "listen() error,error code " << WSAGetLastError() << endl;
return false;
}
cout << "listen ok!" << endl;
HANDLE* hHandle = new HANDLE[nMaxConcurrency];
for (int i = 0; i < nMaxConcurrency; ++i)
{
DWORD dwThreadID = 0;
hHandle[i] = CreateThread(NULL, 0, WorkerThread, &hHandleIocp, 0, &dwThreadID);
}
while (1)
{
sockaddr* addr = NULL;
int* addrLen = 0;
SOCKET client = accept(hSocket, addr, NULL);
if (CreateIoCompletionPort((HANDLE)client, hHandleIocp, 0, 0) == NULL)
{
cout << "Binding client socket to completionPort fail" << GetLastError() << endl;
closesocket(client);
continue;
}
IO_DATA* data = GetOverlapped();
data->Init(TYPE_RECV, client);
DWORD nBytes = 1024, dwFlags = 0;
int nRet = WSARecv(client, &data->wsabuf, 1, &nBytes, &dwFlags, &data->overLapped, NULL);
if (nRet == SOCKET_ERROR && (ERROR_IO_PENDING != WSAGetLastError())){
cout << "WASRecv Failed::Reason Code::" << WSAGetLastError() << endl;
closesocket(client);
RecycleOverlapped(data);
}
}
closesocket(hSocket);
WSACleanup();
return 0;
}
// client.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <iostream>
#include <WinSock2.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
DWORD _stdcall WorkThread(LPVOID)
{
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(6666);
server.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
const int num = 200;
SOCKET client[num];
for (int i = 0; i < num; ++i)
{
client[i] = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
int flag;
flag = connect(client[i], (sockaddr*)&server, sizeof(server));
if (flag < 0){
cout << "error!" << endl;
return 0;
}
}
cout << "connect success" << endl;
while (1){
int nPos = rand() % 100;
char buffer[1024] = "JFKL;AJKFD;LASFKJDSA;KFDS";
send(client[nPos], buffer, 1024, 0);
memset(buffer, NULL, sizeof(buffer));
int rev = recv(client[nPos], buffer, 1024, 0);
if (rev == 0)
{
continue;
}
}
for (int i = 0; i < num; ++i)
{
closesocket(client[i]);
}
return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
DWORD dwThreadID;
HANDLE handle[5];
for (int i = 0; i < 5; ++i)
{
handle[i] = CreateThread(NULL, 0, WorkThread, NULL, 0, &dwThreadID);
}
WaitForMultipleObjects(5, handle, TRUE, -1);
WSACleanup();
return 0;
}