纯干货
客户端和服务器.h文件
#pragma once
#include <iostream>
#include <Windows.h>
class CTcpSocketBase
{
public:
CTcpSocketBase() = default;
virtual ~CTcpSocketBase() = default;
protected:
virtual bool StartupWsa();
virtual bool CreatSocket(SOCKET& SocketID);
};
class CTcpServer : public CTcpSocketBase
{
public:
CTcpServer(const std::string& szNetAddres, uint32_t nNetPort);
~CTcpServer();
bool StartServer();
private:
bool BindSocket();
bool ListenSocket();
static void ReceiveAllClientsFunc(LPVOID para);
private:
SOCKET m_Socket = INVALID_SOCKET;
std::string m_szNetAddres;
uint32_t m_nNetPort;
};
class CTcpClient : public CTcpSocketBase
{
public:
CTcpClient(const std::string& szNetAddres, uint32_t nNetPort);
~CTcpClient();
bool StartClient();
private:
bool ConnectSocket();
static void ReceiveFromServerFunc(LPVOID para);
private:
SOCKET m_Socket = INVALID_SOCKET;
std::string m_szNetAddres;
uint32_t m_nNetPort;
};
客户端和服务器.cpp文件
#include "NetServerSingleUser.h"
#pragma comment(lib,"ws2_32.lib")
bool CTcpSocketBase::StartupWsa()
{
WSADATA wsaData;
auto Result = ::WSAStartup(MAKEWORD(2, 2), &wsaData);
if (0 != Result)
{
std::cout << "Startup wsa failed. Error codeid:" << Result << std::endl;
return false;
}
return true;
}
bool CTcpSocketBase::CreatSocket(SOCKET &SocketID)
{
SOCKET ServerID = ::socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == ServerID)
{
std::cout << "Creat socket failed. Error codeid:" << WSAGetLastError() << std::endl;
return false;
}
SocketID = ServerID;
return true;
}
CTcpServer::CTcpServer(const std::string& szNetAddres, uint32_t nNetPort)
: m_szNetAddres(szNetAddres), m_nNetPort(nNetPort)
{
}
CTcpServer::~CTcpServer()
{
}
bool CTcpServer::StartServer()
{
SOCKET ClientID = INVALID_SOCKET;
if (!StartupWsa())
{
return false;
}
std::cout << "Startup wsa successful." << std::endl;
if (!CreatSocket(m_Socket))
{
return false;
}
std::cout << "Creat socket successful." << std::endl;
if (!BindSocket())
{
return false;
}
std::cout << "Bind socket successful." << std::endl;
if (!ListenSocket())
{
return false;
}
std::cout << "Listen socket successful." << std::endl;
while (true)
{
ClientID = ::accept(m_Socket, NULL, NULL);
if (INVALID_SOCKET == ClientID)
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
_beginthread(CTcpServer::ReceiveAllClientsFunc, NULL, &ClientID);
}
}
bool CTcpServer::BindSocket()
{
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(m_nNetPort);
serverAddr.sin_addr.S_un.S_addr = inet_addr(m_szNetAddres.c_str());
auto Result = ::bind(m_Socket, (sockaddr*)&serverAddr, sizeof(sockaddr));
if (SOCKET_ERROR == Result)
{
std::cout << "Bind socket failed. Error codeid:" << WSAGetLastError() << std::endl;
return false;
}
return true;
}
bool CTcpServer::ListenSocket()
{
auto Result = ::listen(m_Socket, SOMAXCONN);
if (SOCKET_ERROR == Result)
{
std::cout << "Listen socket failed. Error codeid:" << WSAGetLastError() << std::endl;
return false;
}
return true;
}
void CTcpServer::ReceiveAllClientsFunc(LPVOID para)
{
if (nullptr == para)
{
std::cout << "ClientID is NULL." << std::endl;
return;
}
SOCKET ClientID = *((SOCKET*)para);
char cMsg[200] = { 0 };
sockaddr_in ClientMsg;
int nLen = sizeof(sockaddr);
getpeername(ClientID, (sockaddr*)&ClientMsg, &nLen);
std::cout << "Client(" << ClientMsg.sin_addr.S_un.S_addr << " : " << ClientMsg.sin_port << "): has connected!" << std::endl;
while (true)
{
memset(cMsg, '\0', sizeof(cMsg));
if (::recv(ClientID, cMsg, sizeof(cMsg), NULL) < 0)
{
std::cout << "Receive message failed!" << std::endl;;
return;
}
std::cout << "Client(" << ClientMsg.sin_port << "): " << cMsg << std::endl;
::send(ClientID, "Received,Please send again.", 100, NULL); //其实一般项目,服务端收到客户端消息后,都是需要解析这个消息并返回对应报文的,肯定不会这么随意
}
}
CTcpClient::CTcpClient(const std::string& szNetAddres, uint32_t nNetPort)
: m_szNetAddres(szNetAddres), m_nNetPort(nNetPort)
{
}
CTcpClient::~CTcpClient()
{
}
bool CTcpClient::StartClient()
{
if (!StartupWsa())
{
return false;
}
std::cout << "Startup wsa successful." << std::endl;
if (!CreatSocket(m_Socket))
{
return false;
}
std::cout << "Creat socket successful." << std::endl;
if (!ConnectSocket())
{
return false;
}
std::cout << "Connect socket successful." << std::endl;
_beginthread(CTcpClient::ReceiveFromServerFunc, NULL, &m_Socket);
char cMsg[200] = { 0 };
while (true)
{
memset(cMsg, '\0', sizeof(cMsg));
std::cin.getline(cMsg, 100);
send(m_Socket, cMsg, 100, NULL);
}
}
bool CTcpClient::ConnectSocket()
{
sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(m_nNetPort);
serverAddr.sin_addr.S_un.S_addr = inet_addr(m_szNetAddres.c_str());
auto Result = connect(m_Socket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
if (SOCKET_ERROR == Result)
{
std::cout << "Connect socket failed. Error codeid:" << WSAGetLastError() << std::endl;
return false;
}
return true;
}
void CTcpClient::ReceiveFromServerFunc(LPVOID para)
{
if (nullptr == para)
{
std::cout << "ServerID is NULL." << std::endl;
return;
}
SOCKET ServerID = *((SOCKET*)para);
char CMsg[200] = { 0 };
while (true)
{
memset(CMsg, '\0', sizeof(CMsg));
if (recv(ServerID, CMsg, 200, NULL) < 0)
{
std::cout << "recv fail!" << std::endl;
return;
}
std::cout << "(Server): " << CMsg << std::endl;
}
}
int main(int argc, char *argv[])
{
if (strcmp(argv[1], "-S") == 0)
{
CTcpServer server("127.0.0.1", 23);
server.StartServer();
}
else if (strcmp(argv[1], "-C") == 0)
{
CTcpClient client("127.0.0.1", 23);
client.StartClient();
}
else
{
std::cout << "Parameter error!" << std::endl;
}
return 0;
}
注释:
萌新运行方式:找到编译出来的可执行程序.exe,cmd下运行.exe程序,添加执行参数-S开启服务端,执行参数-C开启客户端,有兴趣扩展将地址和端口作为参数传入