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