#include<iostream> #include<WinSock2.h> using namespace std; #pragma comment(lib,"Ws2_32.lib") const int buf_len=1024; const int nDefaultServerPort=10000; //把用户在命令行输入的地址转换成整数地址,用户输入的地址可以有两种形式: //点分十进制(192.168.1.123)和主机名称形式(localhost) u_long ResolveAddress(const char *szServer); //连接服务器 //参数nServerAddr和nPort都必须是网络字节序 SOCKET ConnectServer(u_long nServerAddr,int nPort); //处理回显业务逻辑 bool ProcessConnection(SOCKET sd); bool ShutdownConnection(SOCKET sd); void DoWork(const char *szServer,int nPort);//客户端主题函数 //命令行参数需要包含服务器地址和端口,如果用户没有输入端口,则使用默认的端口nDefaultServerPort int main(/*int argc,char *argv[]*/) { /*if(argc<2) { return -1; } const char *szServer=argv[1]; int nPort=nDefaultServerPort; if(argc>=3) { nPort=atoi(argv[2]); }*/ char *szServer="localhost"; int nPort=nDefaultServerPort; WSAData wsaData; int nCode; if((nCode=WSAStartup(MAKEWORD(2,2),&wsaData))!=0) { cout<<"WSAStartup error"<<nCode<<endl; return -1; } DoWork(szServer,nPort); WSACleanup(); return 0; } u_long ResolveAddress(const char *szServer) { //首先尝试使用inet_addr来转换点分十进制地址,如果返回的是INADDR_NONE,则 //表明szServer使用的是主机名称形式,此时需要调用gethostbyname来查询其地址 u_long nAddr=inet_addr(szServer); if(nAddr==INADDR_NONE) { hostent *ent=gethostbyname(szServer); if(ent==NULL) { cout<<"gethostbyname error"<<WSAGetLastError()<<endl; } else { nAddr=*((u_long*)ent->h_addr_list[10]); } } if(nAddr==INADDR_NONE) { cout<<"Error resolving address"<<endl; } return nAddr; } SOCKET ConnectServer(u_long nServerAddr,int nPort) { //创建一个套接字 SOCKET sd=socket(AF_INET,SOCK_STREAM,0); if(sd==INVALID_SOCKET) { cout<<"socket error"<<WSAGetLastError()<<endl; return INVALID_SOCKET; } //填充服务器套接字地址 sockaddr_in saServer; saServer.sin_family=AF_INET; saServer.sin_addr.s_addr=nServerAddr; saServer.sin_port=nPort; //调用connect 来连接到远程服务器 if(connect(sd,(sockaddr*)&saServer,sizeof(sockaddr_in))==SOCKET_ERROR) { cout<<"connect error"<<WSAGetLastError()<<endl; closesocket(sd); return INVALID_SOCKET; } return sd; } bool ProcessConnection(SOCKET sd) { char buff[buf_len]; //循环直至用户输入Ctrl+Z while(cin>>buff) { int len=(int)strlen(buff); int nSent=0; //把用户的输入发送到服务器 while(nSent<len) { int nTemp=send(sd,&buff[nSent],len-nSent,0); if(nTemp>0) { nSent+=nTemp; } else if(nTemp==SOCKET_ERROR) { cout<<"send error"<<WSAGetLastError()<<endl; return false; } else { cout<<"Connection closed unexpectedly by peer"<<endl; return true; } } //接收服务器回显的数据。由于前面客户端发送了len个字节给服务器,因此 //这里客户端必须从服务器接收len个字节 int nRecv=0; while(nRecv<len) { int nTemp=recv(sd,&buff[nRecv],len-nRecv,0); if(nTemp>0) { nRecv+=nTemp; } else if(nTemp==SOCKET_ERROR) { cout<<"recv error"<<WSAGetLastError()<<endl; return false; } else { cout<<"Connection closed unexpectedly by peer"<<endl; return true; } } //把服务器回显的数据输出到屏幕 buff[nRecv]=0; cout<<buff<<endl; } return true; } void DoWork(const char *szServer,int nPort) { //首先调用ResolveAddress来把用户输入的地址转换成整数地址 u_long nServerAddr=ResolveAddress(szServer); if(nServerAddr==INADDR_NONE) { return; } //第一阶段,连接服务器 SOCKET sd=ConnectServer(nServerAddr,htons(nPort)); if(sd==INVALID_SOCKET) { return; } //第二阶段,处理回显业务逻辑 if(ProcessConnection(sd)==true) { //第三阶段,关闭连接 ShutdownConnection(sd); } } 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<<"unexpected bytes received"<<endl; } }while(nRecv!=0); if(closesocket(sd)==SOCKET_ERROR) { cout<<"Closesocket error"<<WSAGetLastError()<<endl; return false; } return true; }