#pragma once
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#define DATA_BUFSIZE 512
enum { READ, WRITE };
typedef struct io_operation_data
{
OVERLAPPED overlapped;
WSABUF databuf;
CHAR buffer[DATA_BUFSIZE];
BYTE type;
DWORD length;
}IO_OPERATION_DATA;
class IOCP
{
public:
IOCP(SOCKET s, SOCKADDR_IN sin);
virtual ~IOCP();
BOOL recvAsynData();
BOOL sendAsynData();
public:
SOCKET m_s;
SOCKADDR_IN m_sin;
IO_OPERATION_DATA m_io;
};
#include "IOCP.h"
#include <process.h>
#include <list>
std::list<IOCP*> iocpList;
HANDLE hComPort = NULL;
IOCP::IOCP(SOCKET s, SOCKADDR_IN sin)
{
m_s = s;
m_sin = sin;
}
IOCP::~IOCP()
{
}
BOOL IOCP::recvAsynData()
{
DWORD flags = 0L;
DWORD length = 0L;
ZeroMemory(&m_io, sizeof (IO_OPERATION_DATA));
m_io.type = READ;
m_io.databuf.buf = m_io.buffer;
m_io.databuf.len = DATA_BUFSIZE;
if (WSARecv(m_s, &m_io.databuf, 1, &length, &flags, &m_io.overlapped, NULL) == SOCKET_ERROR){
if (ERROR_IO_PENDING != WSAGetLastError()){
return FALSE;
}
}
return TRUE;
}
BOOL IOCP::sendAsynData()
{
DWORD flags = 0L;
DWORD length = 0L;
m_io.type = WRITE;
m_io.databuf.buf = m_io.buffer;
m_io.databuf.len = strlen(m_io.buffer);
if (WSASend(m_s, &m_io.databuf, 1, &length, flags, (LPOVERLAPPED)&m_io, NULL) == SOCKET_ERROR){
if (ERROR_IO_PENDING != WSAGetLastError()){
return FALSE;
}
}
return TRUE;
}
void eraseIocp(IOCP* iocp)
{
std::list<IOCP*>::iterator iter = iocpList.begin();
for (; iter != iocpList.end(); ++iter){
if ((*iter) == iocp){
iocpList.erase(iter);
break;
}
}
}
unsigned int __stdcall service_work_thread(void* context)
{
DWORD dwIoSize;
IOCP* iocp;
LPOVERLAPPED lpoverlapped;
while (true){
Sleep(2000);
dwIoSize = -1;
lpoverlapped = NULL;
iocp = NULL;
BOOL ret = GetQueuedCompletionStatus(hComPort, &dwIoSize, (LPDWORD)&iocp, &lpoverlapped, INFINITE);
if (iocp == NULL && lpoverlapped == NULL){//PostQueuedCompletionStatus
break;
}
if (!ret){
printf("err\n");
DWORD dwIoErr = GetLastError();
if (dwIoErr == WAIT_TIMEOUT){
continue;
}
else if (NULL != lpoverlapped){
eraseIocp(iocp);
}
else{
break;
}
}
else{
if (0 == dwIoSize){
eraseIocp(iocp);
continue;
}
IO_OPERATION_DATA* pIO = CONTAINING_RECORD(lpoverlapped, IO_OPERATION_DATA, overlapped);
switch (pIO->type){
case READ:
iocp->m_io.length = dwIoSize;
iocp->m_io.buffer[iocp->m_io.length] = '\0';
//printf("read:%s\n", iocp->m_io.buffer);
char buffer[64];
sprintf_s(buffer, 64, "hi iocp msg.(%d)", iocp->m_s);
strcpy_s(iocp->m_io.buffer, 64, buffer);
iocp->sendAsynData();
break;
case WRITE:
//printf("write:%s\n",iocp->m_io.buffer);
pIO->length = 0;
if (FALSE == iocp->recvAsynData()){
eraseIocp(iocp);
}
break;
default: break;
}
}
}
return 0;
}
int createIoCompletionPort(int port)
{
SYSTEM_INFO systemInfo;
HANDLE hThreadHandle[64];
//创建完成端口
if ((hComPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0)) == NULL){
return -1;
}
GetSystemInfo(&systemInfo);
DWORD cpuNum = systemInfo.dwNumberOfProcessors;
//线程池
for (unsigned int i = 0; i < cpuNum * 2; ++i){
if ((hThreadHandle[i] = (HANDLE)_beginthreadex(NULL, 0, service_work_thread, hComPort, 0, NULL)) == NULL){
return -1;
}
}
int ret = 0;
WSADATA wsaData;
if ((ret = WSAStartup(0x0202, &wsaData)) != 0){
return -1;
}
SOCKET sListen = INVALID_SOCKET;
if ((sListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET){
WSACleanup();
return -1;
}
SOCKADDR_IN sin;
sin.sin_family = AF_INET;
sin.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
sin.sin_port = htons(port);
if (bind(sListen, (SOCKADDR*)&sin, sizeof(sin)) == SOCKET_ERROR){
closesocket(sListen);
WSACleanup();
return -1;
}
if (listen(sListen, SOMAXCONN)){
closesocket(sListen);
WSACleanup();
return -1;
}
SOCKET sAccept = INVALID_SOCKET;
SOCKADDR_IN saddr_in;
int length = sizeof(saddr_in);
int total = 0;
while (true){
if ((sAccept = WSAAccept(sListen, (SOCKADDR*)&saddr_in, &length, NULL, 0)) == SOCKET_ERROR){
break;
}
++total;
if (total % 10 == 0){
printf("accept client count(%d)\n", total);
}
IOCP* iocp = new IOCP(sAccept, saddr_in);
iocpList.push_back(iocp);
//绑定完成端口
if (CreateIoCompletionPort((HANDLE)sAccept, hComPort, (DWORD)iocp, 0) == NULL){
return -1;
}
if (!iocp->recvAsynData()){
eraseIocp(iocp);
}
}
//销毁线程池
for (unsigned int i = 0; i < cpuNum * 2; ++i){
PostQueuedCompletionStatus(hComPort, 0, NULL, NULL);
CloseHandle(hThreadHandle[i]);
}
WaitForMultipleObjects(cpuNum * 2, hThreadHandle, TRUE, INFINITE);
return 0;
}
int main(int argc, char* argv[])
{
printf("io completion port.\n");
createIoCompletionPort(8086);
return 0;
}
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#include <stdio.h>
/*
Date |Change
-----------------------------------------
2017-7-31 |SOCKET TCP测试客户端
*/
void tcp_client()
{
SOCKET sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8086);
sin.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if (connect(sClient, (sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR){
closesocket(sClient);
return;
}
char buffer[1024];
sprintf_s(buffer, 1024, "hi client msg.(%d)", sClient);
//Sleep(1000);
int ret = send(sClient, buffer, strlen(buffer), 0);
ret = recv(sClient, buffer, sizeof(buffer), 0);
buffer[ret] = '\0';
//printf("%s\n", buffer);
//closesocket(sClient);
}
int main(int argc, char* argv[])
{
printf("tcp client.\n");
WSADATA wsa;
WSAStartup(MAKEWORD(2, 2), &wsa);
int i = 500000;
while (i--){
tcp_client();
//Sleep(3);
}
WSACleanup();
return 0;
}
原文地址:
https://blog.csdn.net/qingdujun/article/details/76794765?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
关键函数
CreateIoCompletionPort
GetQueuedCompletionStatus
PostQueuedCompletionStatus
说明,其实io完成端口和io重叠很相似,
都是将异步的io 请求提交后 在某个地方等待 io完成的通知。
io重叠 调用 waitformultipleobjects 等待 发来的完成通知,再调用WSAGetOverlappedResult 获取该操作的 结果(成功或失败)
而io完成端口,只是将等待的通知放到了线程中,并且通过返回的参数获得操作的结果。调用的是GetQueuedCompletionStatus函数,这个函数会使线程阻塞,处于等待状态,并不进入睡眠。
这里的GetQueuedCompletionStatus 就类似于上面的waitformultipleobjects和WSAGetOverlappedResult 这两个函数,单数区别在于waitformultipleobjects 会使线程进入睡眠,而GetQueuedCompletionStatus不会使线程睡眠。
我们知道如果线程 频繁的在睡眠态和调度态切换的话,是会发费很多的cpu时间。而前者没有进入睡眠态,所以就比后者要高效些。
这就好比自旋锁比互斥锁的效率高一样,前者不会进入睡眠,后者会