惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

T
Threat Research - Cisco Blogs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
V
Vulnerabilities – Threatpost
GbyAI
GbyAI
P
Proofpoint News Feed
L
LINUX DO - 热门话题
P
Palo Alto Networks Blog
A
About on SuperTechFans
T
Tenable Blog
M
MIT News - Artificial intelligence
IT之家
IT之家
I
Intezer
D
DataBreaches.Net
爱范儿
爱范儿
T
Threatpost
C
CERT Recently Published Vulnerability Notes
云风的 BLOG
云风的 BLOG
博客园 - 三生石上(FineUI控件)
WordPress大学
WordPress大学
K
Kaspersky official blog
大猫的无限游戏
大猫的无限游戏
A
Arctic Wolf
Y
Y Combinator Blog
Cyberwarzone
Cyberwarzone
酷 壳 – CoolShell
酷 壳 – CoolShell
D
Darknet – Hacking Tools, Hacker News & Cyber Security
H
Help Net Security
Microsoft Security Blog
Microsoft Security Blog
Spread Privacy
Spread Privacy
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
AWS News Blog
AWS News Blog
博客园 - 聂微东
C
Check Point Blog
S
Securelist
有赞技术团队
有赞技术团队
雷峰网
雷峰网
aimingoo的专栏
aimingoo的专栏
Last Week in AI
Last Week in AI
Stack Overflow Blog
Stack Overflow Blog
MongoDB | Blog
MongoDB | Blog
D
Docker
G
GRAHAM CLULEY
T
The Exploit Database - CXSecurity.com
C
Cybersecurity and Infrastructure Security Agency CISA
T
Tailwind CSS Blog
L
Lohrmann on Cybersecurity
G
Google Developers Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
L
LangChain Blog

博客园 - dgz

c/c++之预处理 派生类的拷贝构造函数 虚函数和接口的差别 CALLBACK 函数 vc中LNK2001错误以及解决方案(转载) C++类对象的拷贝构造函数(转载) C++的static关键字(转载) 指针常量,常量指针 static 和 const的解释(转载) 数据类型转换:static_cast,const_cast等用法(转载) static用法小结(转载) Windows多线程多任务设计初步 SOCKET模型之重叠I/O篇(转贴) WindowsSockets2.0:使用完成端口高性能,可扩展性Winsock服务程序(转载) CListCtrl 使用技巧(转载) C++字符串—— Win32 字符编码 com+调试 com+返回recordset 如何在VC++ 编写的组件中使用 ADO
最简单的完成端口代码
dgz · 2006-06-26 · via 博客园 - dgz

一起来分析一下最简单的完成端口代码#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#include <assert.h>

#include "Socket5.h"

void main(void)
{
//变量声明
WSADATA wsaData;
DWORD Ret;
HANDLE CompletionPort;
SYSTEM_INFO SystemInfo;
DWORD i;
DWORD ThreadID;
SOCKET Listen;
SOCKADDR_IN InternetAddr;
SOCKET Accept;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
DWORD Flags;
DWORD RecvBytes;

//初始化WinSock2
if ((Ret = WSAStartup(0x0202, &wsaData)) != 0)
{
printf("WSAStartup failed with error %u\n", Ret);
return;
}
//创建完成端口对象
if((CompletionPort=CreateIoCompletionPort(INVALID_HANDLE_value,NULL,0,0))==NULL)
{
printf( "CreateIoCompletionPort failed with error: %u\n", GetLastError());
return;
}
//判断CPU数量
GetSystemInfo(&SystemInfo);
printf("您的机器有%d个CPU\n",SystemInfo.dwNumberOfProcessors);
//为每个CPU建立一个工作线程
for(i=0;i<SystemInfo.dwNumberOfProcessors;i++)
{
HANDLE ThreadHandle;
if((ThreadHandle=CreateThread(NULL,0,ServerWorkerThread,CompletionPort,0,&ThreadID)) == NULL)
{
printf("CreateThread() failed with error %u\n", GetLastError());
return;
}
CloseHandle(ThreadHandle);
}
//创建一个Socket用于监听服务端口
if((Listen=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
return;
}
//绑定监听端口
InternetAddr.sin_family=AF_INET;
InternetAddr.sin_addr.s_addr=htonl(INADDR_ANY);
InternetAddr.sin_port = htons(SOCKS_PORT);
if(bind(Listen,(PSOCKADDR)&InternetAddr,sizeof(InternetAddr))==SOCKET_ERROR)
{
printf("bind() failed with error %d\n", WSAGetLastError());
return;
}
//监听
if(listen(Listen,5)==SOCKET_ERROR)
{
printf("listen() failed with error %d\n", WSAGetLastError());
return;
}

printf("Server started at port : %d\n",SOCKS_PORT);

//接受每一个连接并将其关联到完成端口上
while(TRUE)
{
//接受连接
if((Accept=WSAAccept(Listen,NULL,NULL,NULL,0))==SOCKET_ERROR)
{
printf("WSAAccept() failed with error %d\n", WSAGetLastError());
return;
}
printf(" Client Socket number %d connected\n", Accept);

//创建包含接受的Socket信息的单句柄数据结构体
if((PerHandleData=(LPPER_HANDLE_DATA)GlobalAlloc(GPTR,sizeof(PER_HANDLE_DATA)))==NULL)
{
printf("GlobalAlloc() failed with error %u\n", GetLastError());
return;
}

//将Accept关联到完成端口

if(CreateIoCompletionPort((HANDLE)Accept,CompletionPort,(DWORD)PerHandleData,0)==NULL)
{
printf("CreateIoCompletionPort failed with error %u\n", GetLastError());
return;
}
//创建单I/O操作数据
if((PerIoData=(LPPER_IO_OPERATION_DATA)GlobalAlloc(GPTR,sizeof(PER_IO_OPERATION_DATA)))==NULL)
{
printf("GlobalAlloc() failed with error %u\n", GetLastError());
return;
}

PerHandleData->self=Accept;
PerHandleData->isClient=TRUE;
PerHandleData->SelfPerHandleData=PerHandleData;
PerHandleData->SelfPerIoData=PerIoData;

//接收客户端的版本信息
ZeroMemory(&(PerIoData->Overlapped), sizeof(OVERLAPPED));
PerIoData->Operation=OP_READ;
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() failed with error %d\n", WSAGetLastError());
return;
}
}
}
}

DWORD WINAPI ServerWorkerThread(LPVOID CompletionPortID)
{
HANDLE CompletionPort=(HANDLE)CompletionPortID;
DWORD BytesTransferred;
LPPER_HANDLE_DATA PerHandleData;
LPPER_IO_OPERATION_DATA PerIoData;
   DWORD Flags;
DWORD RecvBytes;

while(TRUE)
{
//使用GetQueuedCompletionStatus查询
if(GetQueuedCompletionStatus(CompletionPort,&BytesTransferred,(LPDWORD)&PerHandleData,(LPOVERLAPPED *)&PerIoData,INFINITE)==0)
{
int iError=GetLastError();
printf("GetQueuedCompletionStatus failed with error %u\n", iError);
if(iError==64)
{
continue;
}
else
{
printf("return 0\n");
return 0;
}
}
if(BytesTransferred==0)
{
//远端断开连接,关闭本机SOCKET
printf("Closing ");
if(PerHandleData->isClient==TRUE)
printf("Client");
else
printf("Dest");
printf(" socket %u\n", PerHandleData->self);

closesocket(PerHandleData->self);

//在此关闭和此SOCKET相关联的SOCKET
printf("Closing ");
if(PerHandleData->isClient==TRUE)
printf("Dest");
else
printf("Client");
printf(" socket %u\n", PerHandleData->other);
closesocket(PerHandleData->other);

GlobalFree(PerHandleData->OtherPerHandleData->SelfPerIoData);
GlobalFree(PerHandleData->OtherPerHandleData);

GlobalFree(PerHandleData);
GlobalFree(PerIoData);
continue;
}

switch(PerIoData->Operation)
{
case OP_READ:

       WSARecv(PerHandleData->self,&PerHandleData->SelfPerIoData->DataBuf ,1,&RecvBytes,&Flags,&(PerHandleData->SelfPerIoData->Overlapped),NULL);
   printf("%s\n",PerHandleData->SelfPerIoData->DataBuf.buf);  //显示收到的数据
break;

case OP_WRITE:
printf("write...");
break;

case OP_ACCEPT:
printf("accept...");
break;
}//end of switch

}//end of while
return 0;
}//end of function

为什么我客户连接好以后 只能显示第一次发送的数据。。。以后发送数据就显示不出来了????