目录
实现功能:
服务端实现流程:
客户端实现流程
运行结果
其他问题
//链接相关库
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0)//WSAStartup返回0表示设置初始化成功
{
std::cout << "添加相关链接库失败" << std::endl;
return false;
}
/*创建套接字*/
//AF_INET表示IPv4,SOCK_STREAM数据传输方式,IPPROTO_TCP传输协议;
listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (listenSocket == INVALID_SOCKET)
{
printf("套接字创建失败");
closesocket(listenSocket);
return false;
}
//绑定端口
sockaddr_in addrListen;
addrListen.sin_family = AF_INET; //指定IP格式
addrListen.sin_port = htons(20001); //绑定端口号
addrListen.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");// INADDR_ANY表示任何IP
if (bind(listenSocket, (SOCKADDR*)&addrListen, sizeof(SOCKADDR)) == SOCKET_ERROR)
{
printf("绑定失败");
closesocket(listenSocket);
return false;
}
/*开始监听*/
if (listen(listenSocket, 5) == SOCKET_ERROR)
{
printf("监听出错");
closesocket(listenSocket);
return false;
}
//开启线程
_revDataThead = new std::thread(&TcpServerImpl::RevData, this);
//等待链接函数
Bool WaitClientConnect()
{
/*等待连接,连接后建立一个新的套接字*/
//对应此时所建立连接的套接字的句柄
sockaddr_in remoteAddr; //接收连接到服务器上的地址信息
int remoteAddrLen = sizeof(remoteAddr);
/*等待客户端请求,服务器接收请求*/
revSocket = accept(listenSocket, (SOCKADDR*)&remoteAddr, &remoteAddrLen); //等待客户端接入,直到有客户端连接上来为止
if (revSocket == INVALID_SOCKET)
{
printf("客户端发出请求,服务器接收请求失败:\n", WSAGetLastError());
closesocket(revSocket);
return false;
}
else
{
printf("客服端与服务器建立连接成功:%s \n", inet_ntoa(remoteAddr.sin_addr));
return true;
}
}
//数据接收线程
void TcpServerImpl::RevData()
{
while (1)//用于阻塞,重新等待链接(客户端断开后重新连接)
{
printf("等待连接...\n");
if (WaitClientConnect())
{
char revData[200];
memset(revData, 0, sizeof(revData));
while (recv(revSocket, revData, 200, 0) > 0)//用于阻塞接受多个多个客户端,当返回值 <0 or ==0 均需要重新等待客户端连接
{
printf("接收到客户端发送的数据: %s\n", revData);
//收到数据TODO处理
//------------测试,收到客户端的数据后回复----begin-----
std::string str = "朕已阅";
char sendstr[200];
memset(sendstr, 0, 200);
memcpy(sendstr, str.c_str(), sizeof(str));
SendData(sendstr);
//------------测试-----------------------------end--------
}
}
closesocket(revSocket);
Sleep(1000);
}
}
void TcpServerImpl::SendData(char*sendData)
{
if (send(revSocket, sendData, strlen(sendData), 0) == SOCKET_ERROR)
{
printf("服务端send()出现错误 : %d\n", WSAGetLastError());;
}
else
{
printf("服务端发送数据:%c 成功!\n", sendData);
}
}
//链接相关库
WORD sockVerson = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVerson, &wsaData) != 0)
{
return false;
}
//单开线程保持与服务端的联系,连接成功后等待服务端的消息
revDataThead = new std::thread(&TcpClientImpl::RevData,this);
bool TcpClientImpl::CreateSocketAndConnect()
{
//建立客户端socket
clientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET)
{
printf("套接字创建失败: %d \n", WSAGetLastError());
closesocket(clientSocket);
clientSocket = NULL;
return false;
}
//定义要连接的服务器地址
sockaddr_in addrConServer;
addrConServer.sin_family = AF_INET;
addrConServer.sin_port = htons(20001);
addrConServer.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
if (connect(clientSocket, (SOCKADDR*)&addrConServer, sizeof(addrConServer)) == SOCKET_ERROR)
{
printf("客户端建立连接失败!\n");
closesocket(clientSocket);
clientSocket = NULL;
return false;
}
else
{
printf("客户端建立连接成功,准备发送数据!\n");
return true;
}
}
void TcpClientImpl::RevData()
{
while (1)//尝试重新创建与连接(当服务端断开再启动后,期间需要保持尝试连接)
{
if (CreateSocketAndConnect())
{
char revSerData[200];
memset(revSerData, 0, sizeof(revSerData));
while (recv(clientSocket, revSerData, sizeof(revSerData), 0) > 0)//阻塞进入数据接收阶段,<0或==0情况均需要重新连接
{
printf("服务器发送的数据: %s\n", revSerData);
//接收到服务端数据,TODO处理
}
}
else
{
Sleep(1000);
continue;
}
closesocket(clientSocket);
clientSocket = NULL;
Sleep(1000);
}
}
bool TcpClientImpl::SendData(char* buffer)
{
//发送数据
int sendRes = send(clientSocket, buffer, (int)strlen(buffer), 0);
if (sendRes == SOCKET_ERROR)
{
printf("客户端send()出现错误 : %d\n", WSAGetLastError());
return false;
}
else
printf("客户端发送数据:%c 成功!\n", buffer);
}
后面遇到涉及在线程中怎么将数据发出到其他线程或者线程以外的对象处理的问题,想了几种方案:
注:本文采用VS2015编译