实验一
实验过程:
1.在socket s上投递WSARecv等待接收数据
2.Client发送数据
3.WSARecv成功接收
4.在s上投递WSASend进行数据发送
5.Client成功接收到数据
6.Server进入发送完成后处理,closesocket(s),并再次投递WSARecv(s...)
结果:WSARecv直接以ret=-1,GetLastError()=10038返回,(10038,在一个非套接字上尝试了一个操作)
7.Client再次发送数据
结果:Client显示自己发送成功,Server没有任何反应
实验结论:
在一个已关闭的socket投递WSARecv,则直接以WSARecv(s...)=-1,GetLastError()=10038返回,表异步请求投递失败、IOCP对请求予以忽视。
试验结果图:
实验二
实验过程:
1.在socket s上投递WSARecv编号0,再次投递WSARecv编号12.客户端发数据”xiaogushihaoren“
3.0号WSARecv接收数据,并回发"you you you"
4.Client成功接到"you you you"
5.Server进入发送完成后处理,closesocket(s)
实验结果:
1号WSARecv马上从GetQueuedCompletionStatus以ret=false,dwNum=0,GetLastError()=64返回,(64,指定的网络名不再可用)
实验结论:
已投递成功的WSARecv,己方closesocket(s)关闭socket,则GetQueuedCompletionStatus以ret=false,dwNum=0, GetLastError()=64返回。
结合Client跳过closesocket直接退出试验结果,得出以下结论:
Client直接退出和己方调用closesocket关闭socket造成的影响相同:
之前投递的WSARecv均以三参数ret=false,dwNum=0,GetLastError()=64返回
实验结果图:
实验三
AlarmServer二期开发中遇到的现象:
Client连接到来,Server调用closesocket(s),使用netstat -ano|findstr "4444" 现象:Server中的socket处于FIN_WAIT_2,Client中的socket处于CLOSE_WAIT,符合四步握手关闭TCP
Client连接到来,Server在s上投递WSARecv,Server调用closesocket(s),使用netstat-ano|findstr "4444" 现象:Server和Client中的socket跳过四步握手直接关闭,两端socket均呈再次可用状态
实验结论:
条件:s上的WSARecv正等待数据到来,己方调用closesocket(s)关闭连接
结果:无论Client是否退出或closesocket,Server与Client的socket连接直接跳过四步分手强行关闭,两端socket均呈CLOSED可再次使用状态
实验二与实验三代码:
大体相同只需稍加改变
#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 1024 enum 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; //第一项必须为OVERLAPPED SOCKET cs; //记录客户端socket char 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_IN addr; addr.sin_family = AF_INET; addr.sin_addr.S_un.S_addr = INADDR_ANY; addr.sin_port = htons(4444); 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; // ppiod->buf[dwNum] = ' '; std::cout<<ppiod->no<<" "<<ppiod->buf<<std::endl; ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED)); ppiod->operationType = OP_SEND; memset(ppiod->buf, 0, BUF_LEN); strcpy(ppiod->buf, "you you you"); WSABUF databuf; databuf.buf = ppiod->buf; databuf.len = strlen(ppiod->buf); DWORD dwRecv = 0; DWORD dwFlags = 0; WSASend(pphd->s, &databuf, 1, &dwRecv, dwFlags, &ppiod->overlapped, NULL); } else if(OP_SEND == type) { // std::cout<<"发送完成"<<std::endl; std::cout<<"完成发送的端口号 : "<<pphd->s<<std::endl; // ZeroMemory(&(ppiod->overlapped), sizeof(OVERLAPPED)); ppiod->operationType = OP_RECV; WSABUF databuf; databuf.buf = ppiod->buf; databuf.len = BUF_LEN; /*******************/ closesocket(pphd->s); /*******************/ /*DWORD dwRecv = 0; DWORD dwFlags = 0; int ret = WSARecv(pphd->s, &databuf, 1, &dwRecv, &dwFlags, &ppiod->overlapped, NULL); if(ret != 0 && GetLastError() != WSA_IO_PENDING) { std::cout<<"Post WSARecv Failed: "<<GetLastError()<<std::endl; closesocket(pphd->s); delete pphd; delete ppiod; }*/ } 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_RECV; ppiod->no = 0; WSABUF databuf; databuf.buf = ppiod->buf; databuf.len = BUF_LEN; DWORD dwRecv = 0; DWORD dwFlags = 0; WSARecv(p->s, &databuf, 1, &dwRecv, &dwFlags, &ppiod->overlapped, NULL); PostRecv(p->s, 1); 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; }
客户端实验代码:
#include <WinSock2.h> #include <Windows.h> #include <iostream> #include <string> #include <process.h> #pragma comment(lib, "Ws2_32.lib") int main() { WSADATA ws; if(WSAStartup(MAKEWORD(2, 2), &ws) != 0) return false; SOCKET s = socket(AF_INET, SOCK_STREAM, 0); if(INVALID_SOCKET == s) return false; sockaddr_in addr = {0}; addr.sin_addr.S_un.S_addr = inet_addr("192.168.15.14"); addr.sin_family = AF_INET; addr.sin_port = htons(4444); int ret = connect(s, (sockaddr*)&addr, sizeof(addr)); if(SOCKET_ERROR == ret) { std::cout<<"Connect Server Failed : "<<GetLastError()<<std::endl; return -1; } std::string str = "xiaogushihaoren"; ret = send(s, str.c_str(), str.length(), 0); if(SOCKET_ERROR == ret) { std::cout<<"Send Data Failed : "<<GetLastError()<<std::endl; return -1; } char ch[100] = {0}; ret = recv(s, ch, 100, 0); if(0 == ret) { std::cout<<"Peer Close The Connection"<<std::endl; return -1; } else if(SOCKET_ERROR == ret) { std::cout<<"Recv Data Failed : "<<GetLastError()<<std::endl; return -1; } std::cout<<ch<<std::endl; std::cout<<"fasong?"<<std::endl; std::cin.get(); { std::string str = "xiaogushihaoren"; ret = send(s, str.c_str(), str.length(), 0); if(SOCKET_ERROR == ret) { std::cout<<"Send Data Failed : "<<GetLastError()<<std::endl; return -1; } else std::cout<<"成功发送数据:"<<str<<std::endl; } std::cin.get(); //closesocket(s); return 0; }