• C++网络编程之服务器编程


    #include<iostream>
    #include<WinSock2.h>
    using namespace std;
    #pragma comment(lib,"Ws2_32.lib")
    const int nDefaultServerPort=10000;
    const int buf_len=1024;
    SOCKET AcceptConnection(SOCKET sdListen);
    bool ProcessConnection(SOCKET sd);
    bool ShutdownConnection(SOCKET sd);
    SOCKET BindListen();
    void DoWork();
    int main()
    {
    	WSAData wsaData;
    	int nCode;
    	if((nCode=WSAStartup(MAKEWORD(2,2),&wsaData))!=0)
    	{
    		cout<<"WSAStartup error"<<nCode<<endl;
    		return -1;
    	}
    	DoWork();
    	WSACleanup();
    	return 0;
    }
    void DoWork()
    {
        //获取监听套接字并进入监听状态
    	SOCKET sdListen=BindListen();
    	if(sdListen==INVALID_SOCKET)
    	{
    		return;
    	}
    	//服务器主循环
    	while(true)
    	{
    		SOCKET sd=AcceptConnection(sdListen);
    		if(sd==INVALID_SOCKET)
    		{
    			break;
    		}
    		//第二阶段,服务一个客户端连接
    		if(ProcessConnection(sd)==false)
    		{
    			break;
    		}
    		//第三阶段,关闭一个客户端连接
    		if(ShutdownConnection(sd)==false)
    		{
    			break;
    		}
    		//关闭监听套接字
    		if(closesocket(sdListen)==SOCKET_ERROR)
    		{
    			cout<<"closesocket error"<<WSAGetLastError()<<endl;
    		}
    	}
    }
    SOCKET BindListen()
    {
    	//创建一个监听套接字
    	SOCKET sd=socket(AF_INET,SOCK_STREAM,0);
    	if(sd==INVALID_SOCKET)
    	{
    		cout<<"socket error"<<WSAGetLastError()<<endl;
    		return INVALID_SOCKET;
    	}
    	//填充本地套接字
    	//这里使用了通配地址INADDR_ANY。当然也可以指明一个具体的本地IP地址,但是如果使用通配地址
    	//我们可以接受来自所有网络接口的连接请求。这对于带有多个网卡的服务器来说可以简化编程
    	sockaddr_in saListen;
    	saListen.sin_family=AF_INET;
    	saListen.sin_addr.s_addr=htonl(INADDR_ANY);
    	saListen.sin_port=htons(nDefaultServerPort);
    	//调用bind把本地套接字地址绑定到监听套接字
    	if(bind(sd,(sockaddr*)&saListen,sizeof(sockaddr_in))==SOCKET_ERROR)
    	{
    		cout<<"bind error"<<WSAGetLastError()<<endl;
    		closesocket(sd);
    		return INVALID_SOCKET;
    	}
    	//开始监听
    	if(listen(sd,5)==SOCKET_ERROR)
    	{
    		cout<<"listen error"<<WSAGetLastError()<<endl;
    		closesocket(sd);
    		return INVALID_SOCKET;
    	}
    	return sd;
    }
    //接受一个客户端连接并返回对应于该连接的套接字句柄
    SOCKET AcceptConnection(SOCKET sdListen)
    {
    	sockaddr_in saRemote;
    	int nSize=sizeof(sockaddr_in);
    	SOCKET sd=accept(sdListen,(sockaddr*)&saRemote,&nSize);
    	if(sd==INVALID_SOCKET)
    	{
    		cout<<"accept error"<<WSAGetLastError()<<endl;
    	}
    	return sd;
    }
    //服务一个客户端连接,实现回显服务业务逻辑
    bool ProcessConnection(SOCKET sd)
    {
    	char buff[buf_len];
    	int nRecv;
    	//循环直到客户端关闭数据连接
    	do{
    		//接收客户端的数据
    		//由于套接字sd是阻塞模式,对其调用recv将会阻塞,直到recv完成返回。当
    		//recv返回0时,表明客户端完成数据发送并且关闭了连接,此时就可以退出循环
    		nRecv=recv(sd,buff,buf_len,0);
    		if(nRecv==SOCKET_ERROR)
    		{
    			cout<<"recv error"<<WSAGetLastError()<<endl;
    			return false;
    		}
    		else if(nRecv>0)
    		{
    			int nSent=0;
    			//把数据原封不动发回客户端,即回显
    			while(nSent<nRecv)
    			{
    				//这里的send也会阻塞,只有当send返回后,程序才能继续执行
    				int nTemp=send(sd,&buff[nSent],nRecv-nSent,0);
    				if(nTemp>0)
    				{
    					nSent+=nTemp;
    				}
    				else if(nTemp==SOCKET_ERROR)
    				{
    					cout<<"send error"<<WSAGetLastError()<<endl;
    					return false;
    				}
    				else
    				{
    					//send返回0,由于此时nSent<nRecv,也就是说还有数据没有发送出错,所以连接是被客户端意外关闭的
    					cout<<"Connection closed unexpectedly by peer"<<endl;
    					return true;
    				}
    			}
    		}
    	}while(nRecv!=0);
    	cout<<"Connection closed by peer"<<endl;
    	return true;
    }
    //安全关闭一个TCP连接
    bool ShutdownConnection(SOCKET sd)
    {
    	//首先发送一个TCP FIN分段,向对方表明已经完成数据发送
    	if(shutdown(sd,SD_SEND)==SOCKET_ERROR)
    	{
    		cout<<"shutdown error"<<WSAGetLastError()<<endl;
    		return false;
    	}
    	char buff[buf_len];
    	int nRecv;
    	//继续接受对方的数据,直到recv返回0为止
    	do{
    	    nRecv=recv(sd,buff,buf_len,0);
    		if(nRecv==SOCKET_ERROR)
    		{
    			cout<<"recv error"<<WSAGetLastError()<<endl;
    			return false;
    		}
    		else if(nRecv>0)
    		{
    			cout<<nRecv<<"unexcepted bytes received"<<endl;
    		}
    	}while(nRecv!=0);
    	if(closesocket(sd)==SOCKET_ERROR)
    	{
    		cout<<"closesocket error"<<WSAGetLastError()<<endl;
    		return false;
    	}
    	return true;
    }
    

  • 相关阅读:
    js object 常用方法总结
    深入研究js中的位运算及用法
    input事件中文触发多次问题研究
    景点地图开发实战
    炫酷线条动画--svg
    转:绝对干货--WordPress自定义查询wp_query所有参数详细注释
    canvas实例 ---- 制作简易迷宫(一)
    炫酷弹窗效果制作
    js排序算法总结—冒泡,快速,选择,插入,希尔,归并
    js 实现 promise
  • 原文地址:https://www.cnblogs.com/zztong/p/6695273.html
Copyright © 2020-2023  润新知