IOCP十:Client退出后投递WSARecv
来源:互联网 发布:淘宝网店书籍推荐 编辑:程序博客网 时间:2024/05/01 01:40
实验过程:
过程一:
1.Server等待Client到来
2.Client进入
3.Server接受连接,发送"nihaihaoma"
4.Client接收"nihaihaoma",马上退出
5.Server进入发送完成处理,Sleep(8000)
int ret = WSARecv(s,...)投递接收
结果:
WSARecv以ret=SOCKET_ERROR, GetLastError()= 10054失败
(10054远程主机强迫关闭了一个现有的连接)
过程二:
1.Server等待Client到来
2.Client进入
3.Server接受连接,发送"nihaihaoma"
4.Client接收"nihaihaoma",closesocket(s)后马上退出
5.Server进入发送完成处理,Sleep(8000)
int ret = WSARecv(s,...)投递接收
结果:
投递成功
投递成功的WSARecv马上从GetQueuedCompletionStatus以ret=true, dwNum=0, GetLastError()=997返回
(997重叠 I/O 操作在进行中)
深入探索:
netstat -ano | findstr "4444" 查看端口状态,显示出异常:
1.直接退出:连接在Client退出的那刻被暴力关闭,跳过4步握手,不再可用
2.打声招呼再退出:
回调期间:
Client = FIN_WAIT_2
Server = CLOSE_WAIT
回调结束:
Client = TIME_WAIT
Server = CLOSED
符合四步分手优雅关闭连接
综上所述:
1.连接在Client不辞而别的那刻被暴力关闭、跳过4步握手、不再可用——>WSARecv投递在一个不可用连接上,失败在所难免
2.Client调用closesocket(s)再退出,连接在发送回调中仍旧存在、呈Server->Client的单向传输——>WSARecv投递成功
跳出回调IOCP关闭连接,故投递成功的WSARecv从GetQueuedCompletionStatus返回
测试客户端:与IOCP九—Client退出后投递请求相同
实验代码:
#include <WinSock2.h>#include <Windows.h>#include <iostream>#include <process.h>#include <string>#include <MSWSock.h>#include <set>#pragma comment(lib, "Ws2_32.lib")#pragma comment(lib, "Kernel32.lib")#pragma comment(lib, "Mswsock.lib")#define BUF_LEN 1024enum OperateType{OP_RECV,OP_SEND,OP_ACCEPT,};typedef struct PER_HANDLE_DATA{SOCKET s;//记录是哪个socket上的请求SOCKADDR_IN addr;//记录该socket对应的客户端地址和端口}PER_HANDLE_DATA, *LPPER_HANDLE_DATA;typedef struct PER_IO_DATA{OVERLAPPED overlapped;//第一项必须为OVERLAPPEDSOCKET cs;//记录客户端socketchar buf[BUF_LEN];//发送:此buf存储待发送数据,接收:此buf存储到来的数据int operationType;//记录完成的请求类型:是接收?是发送? 还是连接?int no;}PER_IO_DATA, *LPPER_IO_DATA;SOCKET SocketInitBindListen(){SOCKET s = socket(AF_INET, SOCK_STREAM, 0);if(INVALID_SOCKET == s){std::cout<<"create socket failed : "<<GetLastError()<<std::endl;return INVALID_SOCKET;}SOCKADDR_INaddr;addr.sin_family = AF_INET;addr.sin_addr.S_un.S_addr = INADDR_ANY;addr.sin_port = htons(4445);int ret = bind(s, (sockaddr*)&addr, sizeof(addr));if(SOCKET_ERROR == ret){std::cout<<"bind failed : "<<GetLastError()<<std::endl;return SOCKET_ERROR;}ret = listen(s, 10);if(SOCKET_ERROR == s){std::cout<<"listen fail : "<<GetLastError()<<std::endl;return SOCKET_ERROR;}return s;}bool PostAccept(SOCKET listenSocket){SOCKET cs = socket(AF_INET, SOCK_STREAM, 0);if(INVALID_SOCKET == cs){std::cout<<"Create Socket Failed : "<<GetLastError()<<std::endl;return false;}LPPER_IO_DATA ppiod = new PER_IO_DATA;ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));ppiod->operationType = OP_ACCEPT;ppiod->cs = cs;DWORD dwRecv;int len = sizeof(sockaddr_in) + 16;bool ret = AcceptEx(listenSocket, ppiod->cs, ppiod->buf, 0, len, len, &dwRecv, &ppiod->overlapped);if(false == ret && ERROR_IO_PENDING != GetLastError()){std::cout<<"AcceptEx Failed : "<<GetLastError()<<std::endl;return false;}return true;}bool PostSend(SOCKET s, const char *buf, int len){LPPER_IO_DATA ppiod = new PER_IO_DATA;ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));ppiod->operationType = OP_SEND;memset(ppiod->buf, 0, BUF_LEN);memcpy(ppiod->buf, buf, len);WSABUF databuf;databuf.buf = ppiod->buf;databuf.len = len;DWORD dwRecv = 0;DWORD dwFlags = 0;WSASend(s, &databuf, 1, &dwRecv, dwFlags, &ppiod->overlapped, NULL);return true;}bool PostRecv(SOCKET s, int n){LPPER_IO_DATA ppiod = new PER_IO_DATA;ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));ppiod->operationType = OP_RECV;ppiod->no = n;memset(ppiod->buf, 0, BUF_LEN);WSABUF databuf;databuf.buf = ppiod->buf;databuf.len = BUF_LEN;DWORD dwRecv = 0;DWORD dwFlags = 0;int ret = WSARecv(s, &databuf, 1, &dwRecv, &dwFlags, &ppiod->overlapped, NULL);if(SOCKET_ERROR == ret && WSA_IO_PENDING != GetLastError())return false;return true;}unsigned int __stdcall Func(void *arg){SOCKET s = (SOCKET)arg;Sleep(3000);std::string str = "nihaihaoma";PostSend(s, str.c_str(), str.length());_endthreadex(0);return 0;}unsigned int __stdcall ThreadFunc(void *arg){HANDLE hcp = (HANDLE)arg;if(NULL == hcp){std::cout<<"thread arg error"<<std::endl;return -1;}DWORD dwNum = 0;LPPER_HANDLE_DATA pphd;LPPER_IO_DATA ppiod;while(true){bool ret = GetQueuedCompletionStatus(hcp, &dwNum, (LPDWORD)&pphd, (LPOVERLAPPED*)&ppiod, WSA_INFINITE);//线程退出控制,没有释放申请的堆空间,还不完善if(-1 == dwNum){std::cout<<"Thread Exit"<<std::endl;_endthreadex(0);return 0;}int type = ppiod->operationType;//连接关闭if(dwNum == 0 && type != OP_ACCEPT){std::cout<<"The Connection Be Closed: "<<GetLastError()<<std::endl;std::cout<<"ret="<<ret<<" operateType="<<ppiod->operationType<<" no="<<ppiod->no<<std::endl;closesocket(pphd->s);delete pphd;delete ppiod;continue;}//其他错误if(false == ret){std::cout<<"An Error Occurs : "<<GetLastError()<<std::endl;closesocket(pphd->s);delete pphd;delete ppiod;continue;}if(OP_RECV == type){//std::cout<<"接收完成"<<std::endl;std::cout<<"接收端口号 :"<<pphd->s<<std::endl;//}else if(OP_SEND == type){//std::cout<<"发送完成"<<std::endl;std::cout<<"完成发送的端口号 : "<<pphd->s<<std::endl;//Sleep(8000);DWORD errcode;ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));ppiod->operationType = OP_RECV;WSABUF databuf;databuf.buf = ppiod->buf;databuf.len = BUF_LEN;DWORD dwRecv = 0;DWORD dwFlags = 0;std::cout<<"开始投递WSARecv"<<std::endl;int ret = WSARecv(ppiod->cs, &databuf, 1, &dwRecv, &dwFlags, &ppiod->overlapped, NULL);if(SOCKET_ERROR == ret && (errcode = GetLastError()) != WSA_IO_PENDING)std::cout<<"WSARecv Error: "<<errcode<<std::endl;elsestd::cout<<"成功"<<std::endl;}else if(OP_ACCEPT == type){//std::cout<<"连接完成"<<std::endl;//SOCKET cs = ppiod->cs;int len = sizeof(sockaddr_in) + 16;int localLen, remoteLen;LPSOCKADDR localAddr, remoteAddr;GetAcceptExSockaddrs(ppiod->buf, 0, len, len, (SOCKADDR **)&localAddr, &localLen, (SOCKADDR **)&remoteAddr, &remoteLen);LPPER_HANDLE_DATA p = new PER_HANDLE_DATA;p->s = cs;memcpy(&p->addr, remoteAddr, remoteLen);char *ch = inet_ntoa(p->addr.sin_addr);CreateIoCompletionPort((HANDLE)cs, hcp, (DWORD)p, 0);ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED));ppiod->operationType = OP_SEND;ppiod->no = 0;std::string str = "nihaihaoma";strcpy(ppiod->buf, str.c_str());WSABUF databuf;databuf.buf = ppiod->buf;databuf.len = str.length();DWORD dwRecv = 0;DWORD dwFlags = 0;WSASend(cs, &databuf, 1, &dwRecv, dwFlags, &ppiod->overlapped, NULL);PostAccept(pphd->s);PostAccept(pphd->s);}}return 0;}int main(){WSADATA ws;if(WSAStartup(MAKEWORD(2, 2), &ws) != 0){std::cout<<"WSAStartup error : "<<GetLastError()<<std::endl;return -1;}HANDLE hcp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);if(NULL == hcp){std::cout<<"create completion port failed : "<<GetLastError()<<std::endl;return -1;}std::set<HANDLE> setWorkers;SYSTEM_INFO si;GetSystemInfo(&si);for(int i = 0; i < si.dwNumberOfProcessors * 2 + 2; i++){HANDLE worker = (HANDLE)_beginthreadex(NULL, 0, ThreadFunc, (LPVOID)hcp, 0, NULL);if(NULL == worker){std::cout<<"create thread failed : "<<GetLastError()<<std::endl;return -1;}setWorkers.insert(worker);}SOCKET s = SocketInitBindListen();if(INVALID_SOCKET == s){std::cout<<"socket init failed"<<std::endl;return -1;}LPPER_HANDLE_DATA pphd = (LPPER_HANDLE_DATA)GlobalAlloc(GPTR, sizeof(PER_HANDLE_DATA));pphd->s = s;CreateIoCompletionPort((HANDLE)s, hcp, (DWORD)pphd, 0);bool ret = PostAccept(s);if(false == ret){std::cout<<"PostAccept Failed"<<std::endl;return -1;}//退出控制/*std::cin.get();for(int i = 0; i < setWorkers.size(); i++)PostQueuedCompletionStatus(hcp, -1, NULL, NULL);*/auto iter = setWorkers.begin();for(; iter != setWorkers.end(); iter++)WaitForSingleObject(*iter, INFINITE);WSACleanup();std::cin.get();return 0;}
- IOCP十:Client退出后投递WSARecv
- IOCP九:Client退出后投递WSASend
- 【笔记】IOCP投递WSARecv失败10014的解决方法
- 用任务管理器关闭客户端后,服务器的早先投递的WSARecv没有从GetQueuedCompletionStatus返回
- IOCP多次投递
- IOCP (关于WSASend,WSARecv调用)
- IOCP (关于WSASend,WSARecv调用)
- 使用完成端口投递WSARecv出现错误
- IOCP投递进行读操作
- IOCP中多次投递WSASend
- IOCP中多次投递WSASend
- IOCP中多次投递WSASend
- WSARecv
- WSARecv
- WSARecv
- WSARecv
- 关于WSARecv在IOCP使用中程序崩溃的问题
- 重叠I/O完成例程模型如何同时投递WSARecv和WSASend
- Linux常用shell命令
- Android中的Environment.getExternalStorageState使用
- 临界区,互斥量,信号量,事件多线程总结
- 【面试准备】字符串反序
- SEO在未来的发展是否会变更方向
- IOCP十:Client退出后投递WSARecv
- c#的 UDP接收
- 将大型 Page Blob 的页范围进行分段
- oracle 更改时间类型的默认显示方式(从实践中学习Oracle SQL学习笔记 第一章)
- POJ 2663
- 解决linux cp: omitting directory
- HDU--1020:Encoding (字符串)
- showModalDialog/showModelessDialog使用例子
- oflash烧写程序使用说明