• IOCP四:己方closesocket


    实验一

    实验过程:

            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编号1
            2.客户端发数据”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;
    }


  • 相关阅读:
    Winpcap网络开发库入门
    主机字节序与网络字节序的转换
    WORD与DWORD
    TCP/IP各种数据包结构体
    解析IPV4报文 和IPV6 报文的 checksum
    TCP头校验和计算算法详解
    第九次作业:DFA最小化,语法分析初步
    第八次作业:非确定的自动机NFA确定化为DFA
    第七次:正规式、正规文法与自动机
    第六次作业:正规文法与正规式
  • 原文地址:https://www.cnblogs.com/chaikefusibushiji/p/7475632.html
Copyright © 2020-2023  润新知