当前位置: 首页 > article >正文

【C++】创建TCP服务端

实现了一个基本的 TCP 服务器,可以接受多个客户端连接,然后持续接收客户端发送的信息, 最后将接收到的信息再发送回客户端 。

源码 

头文件(TCPServerTest.h)

#include <iostream>
#include <winsock2.h>
#include <ws2tcpip.h>

#include <thread>
#include <functional> // 添加这个头文件以使用 std::bind

#include <string>

#pragma comment(lib, "ws2_32.lib")

class TCPSever {
public:
	TCPSever(int port);
	~TCPSever();
	int createSocket();  //创建套接字
	int serverPreparation();  //服务器连接准备
	int startConnectClient();  //接受连接客户端
	void handleClient(SOCKET clientSocket);  //处理客户端

	int Port;
	WSADATA wsaData;
	SOCKET serverSocket;
	struct sockaddr_in serverAddr, clientAddr;
	int addrLen = sizeof(clientAddr);
};

 源文件(TCPServerTest.cpp)

#include "TCPServerTest.h"

TCPSever::TCPSever(int port):Port(port)
{
	// 初始化 Windows Sockets,传入的参数MAKEWORD(2, 2)指定使用 Winsock 2.2 版本,  成功返回0,失败返回非0的错误值
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {  //
		std::cerr << "Error initializing Winsock\n";
	}
	else
	{
		createSocket();
		serverPreparation();
		startConnectClient();
	}
}

TCPSever::~TCPSever()
{
	closesocket(this->serverSocket);  // 关闭与服务端的连接,关闭服务端套接字
	WSACleanup();  //清理 Winsock 库资源
}

int TCPSever::createSocket()
{
	// 创建套接字
	this->serverSocket = socket(AF_INET, SOCK_STREAM, 0);
	if (this->serverSocket == INVALID_SOCKET) {
		std::cerr << "Error creating socket\n";
		WSACleanup();
		return 1;
	}
}

int TCPSever::serverPreparation()
{
	// 设置服务器地址信息
	this->serverAddr.sin_family = AF_INET;
	this->serverAddr.sin_addr.s_addr = INADDR_ANY;
	this->serverAddr.sin_port = htons(Port);

	// bind 函数 可以绑定套接字到指定地址和端口
	if (bind(this->serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
		std::cerr << "Error binding socket\n";
		closesocket(this->serverSocket);
		WSACleanup();
		return 1;
	}

	// listen函数:开始监听连接,参数10表示等待连接队列的最大长度为 10
	if (listen(this->serverSocket, 10) == SOCKET_ERROR) {
		std::cerr << "Error listening for connections\n";
		closesocket(this->serverSocket);
		WSACleanup();
		return 1;
	}
	std::cout << "Server listening on port " << Port << std::endl;
}

int TCPSever::startConnectClient()
{
	while (true)  //循环接收数据
	{
		SOCKET newClientSocket;
		// 接受客户端连接  accept函数:在循环中等待客户端连接,一旦有客户端连接,会返回一个新的套接字用于与该客户端通信,并获取客户端的地址信息
		newClientSocket = accept(this->serverSocket, (struct sockaddr*)&clientAddr, &addrLen);
		if (newClientSocket == INVALID_SOCKET) {
			std::cerr << "Error accepting connection\n";
			continue;
		}
		char clientIP[INET_ADDRSTRLEN];
		if (inet_ntop(AF_INET, &clientAddr.sin_addr, clientIP, INET_ADDRSTRLEN) == nullptr) {
			std::cerr << "Error converting client IP address\n";
		}
		else {
			std::cout << "Client: " << std::string(clientIP)+ ":" + std::to_string(ntohs(clientAddr.sin_port)) << std::endl;
			std::thread clientThread(std::bind(&TCPSever::handleClient, this, newClientSocket));  //连上后和客户端进行数据
			clientThread.detach();
		}
	}
}

void TCPSever::handleClient(SOCKET clientSocket)
{
	const char* welcomeMessage = "Welcome to the server!\n";
	send(clientSocket, welcomeMessage, strlen(welcomeMessage), 0);  // 向客户端发送信息

	char buffer[1024];
	while (true)
	{
		int bytesRead = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);
		if (bytesRead > 0) {
			buffer[bytesRead] = '\0';
			std::cout << "Received: " << buffer << std::endl;
			std::string response = "received: " + std::string(buffer);
			send(clientSocket, response.c_str(), response.length(), 0);
		}
		else {
			std::cerr << "Connection closed by client\n";
			closesocket(clientSocket);
			return;
		}
	}
}

调用:

#include "TCPServerTest.h"

int main() {
	TCPSever server = TCPSever(8888);
}

结果

可以看到服务端可以支持多个客户端连接 

客户端代码见:

【C++】创建TCP客户端-CSDN博客


http://www.kler.cn/news/362156.html

相关文章:

  • 数据字典是什么?和数据库、数据仓库有什么关系?
  • 实战华为AC6508无线控制器+华为无线AP上线配置(AirEngine5762S-12+AirEngine5760-10)+无线WIFI配置
  • 深入解析 Jenkins 自动化任务链:三大方法实现任务间依赖与状态控制
  • (北京政务服务满意度公司)满意度调查助力服务质量提升
  • 听泉鉴宝在三个月前已布局商标注册!
  • YOLOv11[基础]】热力图可视化实践② | 视频版 | 输入为视频文件
  • DLNA—— 开启智能生活多媒体共享新时代
  • 线性可分支持向量机的原理推导 9-23拉格朗日乘子α的最大化问题 公式解析
  • Spring中导致事务传播失效的情况(自调用、方法访问权限、异常处理不当、传播类型选择错误等。在实际开发中,务必确保事务方法正确配置)
  • 回溯法求解简单组合优化问题
  • 初学者怎么入门大语言模型(LLM)?
  • 微积分复习笔记 Calculus Volume 1 - 3.5 Derivatives of Trigonometric Functions
  • 11.学生成绩管理系统(Java项目基于SpringBoot + Vue)
  • rk3568 , rk3588, rtl8211F , 时钟的问题
  • MySQL--mysql的安装
  • 什么是CI/CD
  • 主机本地IP与公网IP以及虚拟机的适配器和WSL发行版的IP
  • 分布式异步任务框架Celery,如何实现代码实时监控
  • 聊聊黑龙江等保测评
  • 人大金仓链接
  • rancher安装并快速部署k8s 管理集群工具
  • C/S 软件架构
  • D39【python 接口自动化学习】- python基础之函数
  • 线下陪玩导游系统软件源码,家政预约服务源码(h5+小程序+app)
  • JVM、字节码文件介绍
  • [ComfyUI]Flux:太酷啦!超震撼电影视觉盛宴!2025生肖灵蛇守护