#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;
}