0.通信步骤流程图(左:服务器;右:客户端;)
1.服务器代码
1.1 服务器类头文件(CServer_Wins.h)
#pragma once
#include <winsock2.h>
class CServer_Wins
{
public:
CServer_Wins();
void RecMsg();
void stopRec();
~CServer_Wins();
private:
bool m_terminal;
SOCKET m_slisten; //创建监听套接字
};
1.2服务器类源文件(CServer_Wins.cpp)
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include "CServer_Wins.h"
#include <iostream>
#include <string>
#pragma comment(lib, "ws2_32.lib")
CServer_Wins::CServer_Wins():m_terminal(false)
{
//必须进行如下初始化, 否则socket()会返回10093错误
//初始化WSA
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0) //通过一个进程初始化ws2_32.dll
{
std::cout << "Initialize WSA failed" << std::endl;
return ;
}
//创建套接字
m_slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_slisten == INVALID_SOCKET)
{
printf("%d\n", WSAGetLastError());
printf("%s\n", "Socket Error!");
return ;
}
struct sockaddr_in sin;
sin.sin_family = AF_INET; //设置地址家族
sin.sin_port = htons(8888); //设置端口号,inet_addr("192.168.1.0");
sin.sin_addr.S_un.S_addr = INADDR_ANY; //设置地址
//绑定端口
if ((bind(m_slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR))
//套接字, 指向sockaddr_in结构体的指针,参数长度
{
printf("%s\n", "Bind Error!");
}
if (listen(m_slisten, 20) == SOCKET_ERROR) //套接字, 为该套接字排队的最大连接数
//此时, slisten 变为监听套接字
{
printf("%s\n", "Listen Error!");
closesocket(m_slisten); //关闭监听套接字
WSACleanup(); //终止Ws2_32.dll的使用
return;
}
}
void CServer_Wins::RecMsg()
{
std::cout << "Rec thread begin ..." << std::endl;
struct sockaddr_in remoteAddr; //存储 通过accept 得到的 客户端IP地址
int nAddrlen = sizeof(remoteAddr); //IP地址长度
while (!m_terminal)
{
//std::cout << "thread is running" << std::endl;
SOCKET sClient = accept(m_slisten, (SOCKADDR*)&remoteAddr, &nAddrlen);
if (sClient == INVALID_SOCKET)
{
printf("accept error !");
continue;
}
char revData[1025]; //接收回来的数据
int ret = 0; //接收回来的字节数
//接收数据
ret = recv(sClient, revData, 1024, 0);
if (ret > 0)
{
revData[ret] = '\0';
std::cout << "Client " << inet_ntoa(remoteAddr.sin_addr) << " say : " << revData << std::endl;
}
//发送数据
send(sClient, "Server get msg!", strlen("Server get msg!"), 0);
//连接套接字, 要发送数据所存储位置对应的地址, 长度
closesocket(sClient); //关闭连接套接字
std::cout << "session end" << std::endl;
Sleep(30);
}
std::cout << "Rec thread end..." << std::endl;
}
void CServer_Wins::stopRec()
{
m_terminal = true;
}
CServer_Wins::~CServer_Wins()
{
std::cout << "~CServer_Wins()" << std::endl;
closesocket(m_slisten); //关闭监听套接字
WSACleanup(); //终止Ws2_32.dll的使用
}
1.3 服务器主函数
#include <iostream>
#include <thread>
#include "CServer_Wins.h"
using namespace std;
int main()
{
CServer_Wins server;
thread rec(&CServer_Wins::RecMsg, &server);
rec.join();
std::cout << "I love China!\n";
return 0;
}
2.客户端代码
2.1客户端类头文件(CClient_Wins.h)
#pragma once
#include <winsock2.h>
class CClient_Wins
{
public:
CClient_Wins();
bool ConnectSerever(char ServerIP[]);
void SendMsg(char ServerIP[], const char SendBuff[]);
void RecMsg();
void stopRecv();
~CClient_Wins();
private:
SOCKET m_cSocket;
bool m_terminate;
};
2.2客户端类源文件(CClient_Wins.cpp)
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include "CClient_Wins.h"
#include <iostream>
#include <string>
#pragma comment(lib, "ws2_32.lib")
struct sockaddr_in sin_client;
CClient_Wins::CClient_Wins():m_terminate(false)
{
//必须进行如下初始化, 否则socket()会返回10093错误
//初始化WSA
WORD sockVersion = MAKEWORD(2, 2);
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0) //通过一个进程初始化ws2_32.dll
{
std::cout << "Initialize WSA failed" << std::endl;
return;
}
}
bool CClient_Wins::ConnectSerever(char ServerIP[])
{
bool ret = false;
sin_client.sin_addr.S_un.S_addr = inet_addr(ServerIP); //设置地址
if (connect(m_cSocket, (sockaddr*)&sin_client, sizeof(sin_client)) == 0)
{
ret = true;
}
return ret;
}
void CClient_Wins::SendMsg(char ServerIP[], const char SendBuff[])
{
//创建套接字
m_cSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_cSocket == INVALID_SOCKET)
{
printf("%d\n", WSAGetLastError());
printf("%s\n", "Socket Error!");
return;
}
sin_client.sin_family = AF_INET; //设置地址家族
sin_client.sin_port = htons(8888); //设置端口号,inet_addr("192.168.1.0");
ConnectSerever(ServerIP);
send(m_cSocket, SendBuff, strlen(SendBuff), 0);
}
void CClient_Wins::RecMsg()
{
char buffer[1025];
int num = 0;
while (!m_terminate)
{
num = recv(m_cSocket, buffer, 1024, 0);//阻塞
if (num > 0)
{
buffer[num] = '\0';
std::cout << "Server say:" << buffer << std::endl;
closesocket(m_cSocket);
}
}
closesocket(m_cSocket); //关闭监听套接字
}
void CClient_Wins::stopRecv()
{
m_terminate = true;
}
CClient_Wins::~CClient_Wins()
{
closesocket(m_cSocket); //关闭监听套接字
WSACleanup(); //终止Ws2_32.dll的使用
}
2.3 客户端主函数
#include <iostream>
#include <thread>
#include <string>
#include "CClient_Wins.h"
using namespace std;
int main()
{
CClient_Wins client;
//getchar();
char IP[] = "127.0.0.1";
client.ConnectSerever(IP);
thread cli(&CClient_Wins::RecMsg, &client);
cout << "Please input send content:" << endl;
string content;
cin >> content;
while (content.compare("stop") != 0)
{
client.SendMsg(IP, content.c_str());
cin >> content;
}
cli.join();
std::cout << "I love China!\n";
return 0;
}
3.效果图
服务器
客户端