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

来源:互联网 发布:赛门铁克软件 编辑:程序博客网 时间:2024/05/17 22:59
#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;}

0 0
原创粉丝点击