zoukankan      html  css  js  c++  java
  • C++ 网络编程 阻塞I/O模型并发回显服务器

    #include<iostream>
    #include<WinSock2.h>
    using namespace std;
    #pragma comment(lib,"Ws2_32.lib")
    const int nPort=10000;
    const int nDefaultBufferSize=1024;
    DWORD WINAPI ThreadProc(LPVOID lpParama)
    {
       SOCKET sd=(SOCKET)lpParama;
       char buff[nDefaultBufferSize];
       int nRecv;
       do{         //循环直到客户端关闭数据连接
    	   nRecv=recv(sd,buff,nDefaultBufferSize,0);  //返回的是接收到的字节数,若为0表示客户端断绝连接
    	   if(nRecv==SOCKET_ERROR)
    	   {//判断接收是否出现异常
    		   cout<<"接收异常"<<WSAGetLastError()<<endl;
    		   return -1;
    	   }
    	   else if(nRecv>0)
    	   {
    		   int nSent=0;
    		   //将数据原封不动的发回去
    		   while(nSent<nRecv)
    		   {
    			   int nTemp=send(sd,&buff[nSent],nRecv-nSent,0);
    			   if(nTemp>0)   //正常发送情况
    			   {
    				   //说明发送出nTemp个字节数据
    				   nSent+=nTemp;//表明到目前为止已发送nSent个字节数据
    			   }
    			   else if(nTemp==SOCKET_ERROR)//发送异常情况
    			   {
    				   cout<<"发送出错"<<WSAGetLastError()<<endl;
    				   return -1;
    			   }
    			   else  //send返回0,表示客户端意外关闭,没有发送完所有的数据客户端就关闭了
    			   {
    				   cout<<"客户端关闭"<<WSAGetLastError()<<endl;
    			   }
    		   }
    	   }
       }while(nRecv!=0);
       cout<<"数据传输完毕,客户端断开连接"<<endl;      //客户端关闭连接后,服务器需要进入第三阶段,即把当前客户端连接关闭
       //首先发送一个FIN字段
       if(shutdown(sd,SD_SEND)==SOCKET_ERROR)
       {
    	   cout<<"发送FIN字段失败"<<WSAGetLastError()<<endl;
    	   return -1;
       }
       char buff1[nDefaultBufferSize];
       int nRecv1;
       //继续接受对方的数据直到recv返回0为止
       do{
    	   nRecv1=recv(sd,buff1,nDefaultBufferSize,0);
    	   if(nRecv1==SOCKET_ERROR)
    	   {
    		   cout<<"接收异常"<<WSAGetLastError()<<endl;
    		   return -1;
    	   }
    	   else if(nRecv1>0)
    	   {
    		   cout<<"接收到不需要的数据"<<endl;
    	   }
       }while(nRecv1!=0);
       if(closesocket(sd)==SOCKET_ERROR)
       {
    	   cout<<"关闭异常"<<WSAGetLastError()<<endl;
    	   return -1;
       }
       return 0;
    }
    int main()
    {
    	WSAData wsaData;
    	int nCode;
    	nCode=WSAStartup(MAKEWORD(2,2),&wsaData);//初始化Winsock库,MAKEWORD(2,2)表示Winsock2.2版本
    	if(nCode!=0)
    	{
    		cout<<"Winsock初始化失败"<<endl;
    		return -1;
    	}
    	SOCKET sdListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//创建一个套接字
    	if(sdListen==INVALID_SOCKET)
    	{
    		//判断创建套接字是否成功
    		cout<<"创建失败"<<endl;
    		return -1;
    	}
    	sockaddr_in sd; //创建本地套接字
    	sd.sin_family=AF_INET;  //表明使用的是IPv4;
    	sd.sin_port=htons(nPort);//用于将主机16位无符号整数字节序转换成网络字节序
    	sd.sin_addr.s_addr=htonl(INADDR_ANY);//用于将主机32为无符号整数字节序转换为网络字节序
    	if(bind(sdListen,(sockaddr*)&sd,sizeof(sockaddr_in))==SOCKET_ERROR)
    	{
    		//判断是否绑定成功
    		cout<<"绑定失败"<<WSAGetLastError()<<endl;
    		closesocket(sdListen);
    		return -1;
    	}
    	if(listen(sdListen,5)==SOCKET_ERROR)
    	{
    		//判断监听是否成功
    		cout<<"监听失败"<<WSAGetLastError()<<endl;
    		closesocket(sdListen);
    		return -1;
    	}
    	while(true)  //进入服务器主循环核心部分
    	{
    		sockaddr_in saClient;//用于保存客户端的地址信息
    		int nSize=sizeof(sockaddr_in);//用于保存客户端地址信息的大小
    		SOCKET sd=accept(sdListen,(sockaddr*)&saClient,&nSize);//从待处理客户连接请求队列中取出第一个,为
    		//该连接请求创建一个新的套接字,并返回该套接字的句柄
    		if(sd==INVALID_SOCKET)
    		{
    			//如果此句柄无效,则突出循环
    			break;
    		}
    		//创建一个新的线程来服务刚刚接受的客户端连接
    		DWORD dwThreadId;
    		HANDLE hThread=CreateThread(0,0,ThreadProc,(LPVOID)sd,0,&dwThreadId);
    		CloseHandle(hThread);
    	}
            if(closesocket(sdListen)==SOCKET_ERROR)
    	{
    		cout<<"关闭总套接字失败"<<WSAGetLastError()<<endl;
    	}
    
    	WSACleanup();//释放资源
    	return 0;
    }
    


    
       
    
    
  • 相关阅读:
    记一份电网信息化建设企业信息分析平台规划
    2018年个人心灵历程记录
    OGG For Bigdata To Kafka同步问题处理
    Vue.js有赞商城(思路以及总结整理)
    汉诺塔-递归算法
    git合并分支
    js实现页面消息滚动效果
    chrome实现网页高清截屏(F12、shift+ctrl+p、capture)
    JS计算时间差
    Socket.io详解
  • 原文地址:https://www.cnblogs.com/zztong/p/6695271.html
Copyright © 2011-2022 走看看