使用C++实现简单的TCP服务器和客户端

devtools/2025/2/26 4:28:47/

使用C++实现简单的TCP服务器和客户端

  • 介绍
  • 准备工作
  • 1. TCP服务器实现
    • 代码结构
    • 解释
  • 2. TCP客户端实现
    • 代码结构
    • 解释
  • 3. 测试
    • 1.编译:
    • 2.运行
  • 结语

介绍

本文将通过一个简单的例子,介绍如何使用C++实现一个基本的TCP服务器和客户端。这个例子展示了如何创建服务器端接收客户端的连接,如何处理接收到的数据,并如何将数据发送回客户端。

我们会分两部分来介绍:

  1. TCP服务器的实现:包括如何创建服务器、监听端口、接收客户端请求等。
  2. TCP客户端的实现:客户端如何连接到服务器、发送数据并接收服务器返回的数据。

准备工作

首先,确保你的开发环境中已经安装了C++编译器(如GCC或Clang)以及支持的标准库。在Linux或类Unix系统上进行开发是最常见的,下面的代码也适用于这种环境。

1. TCP服务器实现

代码结构

首先,来看下TCP服务器的代码实现:

#include <arpa/inet.h>
#include <cstring>
#include <sys/socket.h>
#include <unistd.h>
#include <iostream>
#include <thread>#define SERVER_PORT 12345
#define BUFFER_SIZE 1024class TcpServer {
public:TcpServer(int port);~TcpServer();void Start();void Stop();private:void ListenThreadFunc();void ReceiveThreadFunc(int clientSocket);void CloseListenSocket();void CloseDataSocket();int mListenSocket;int mDataSocket;int mPort;std::unique_ptr<std::thread> mListenThread;bool mRunning;
};TcpServer::TcpServer(int port) : mListenSocket(-1), mDataSocket(-1), mPort(port), mListenThread(nullptr), mRunning(false) {}TcpServer::~TcpServer() {Stop();
}void TcpServer::Start() {if (mRunning) {std::cerr << "Server is already running!" << std::endl;return;}mRunning = true;mListenSocket = socket(AF_INET, SOCK_STREAM, 0);if (mListenSocket == -1) {std::cerr << "Failed to create listen socket!" << std::endl;return;}sockaddr_in serverAddr{};memset(&serverAddr, 0, sizeof(serverAddr));serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(mPort);serverAddr.sin_addr.s_addr = INADDR_ANY;if (bind(mListenSocket, reinterpret_cast<const sockaddr*>(&serverAddr), sizeof(serverAddr)) == -1) {std::cerr << "Failed to bind socket!" << std::endl;CloseListenSocket();return;}if (listen(mListenSocket, 5) == -1) {std::cerr << "Failed to listen on socket!" << std::endl;CloseListenSocket();return;}mListenThread = std::make_unique<std::thread>([this] { ListenThreadFunc(); });
}void TcpServer::Stop() {if (!mRunning) return;mRunning = false;CloseListenSocket();CloseDataSocket();if (mListenThread && mListenThread->joinable()) {mListenThread->join();}
}void TcpServer::ListenThreadFunc() {while (mRunning) {sockaddr_in clientAddr{};socklen_t len = sizeof(clientAddr);int clientSocket = accept(mListenSocket, reinterpret_cast<sockaddr*>(&clientAddr), &len);if (clientSocket == -1) {std::cerr << "Accept failed!" << std::endl;continue;}std::cout << "Client connected!" << std::endl;std::thread receiveThread([this, clientSocket] { ReceiveThreadFunc(clientSocket); });receiveThread.detach();}
}void TcpServer::ReceiveThreadFunc(int clientSocket) {char buffer[BUFFER_SIZE];while (mRunning) {memset(buffer, 0, BUFFER_SIZE);int res = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);if (res <= 0) {std::cerr << "Receive failed or client disconnected!" << std::endl;break;}std::cout << "Received from client: " << buffer << std::endl;send(clientSocket, "Message received", 17, 0);  // Send acknowledgment back}CloseDataSocket();
}void TcpServer::CloseListenSocket() {if (mListenSocket != -1) {close(mListenSocket);mListenSocket = -1;}
}void TcpServer::CloseDataSocket() {if (mDataSocket != -1) {close(mDataSocket);mDataSocket = -1;}
}int main() {TcpServer server(SERVER_PORT);server.Start();std::this_thread::sleep_for(std::chrono::minutes(10)); // Server will run for 10 minutesserver.Stop();return 0;
}

解释

  • TcpServer 类:定义了一个 TcpServer 类来处理服务器的启动、停止以及接收客户端请求。
  • Start() 方法:创建一个监听套接字,绑定端口并开始监听。
  • ListenThreadFunc() 方法:负责监听来自客户端的连接请求。
  • ReceiveThreadFunc() 方法:每个客户端连接都会创建一个新的线程来处理数据接收。

2. TCP客户端实现

代码结构

接下来是客户端的实现。客户端需要连接到服务器,发送请求并接收响应。

#include <iostream>
#include <string>
#include <unistd.h>
#include <arpa/inet.h>
#include <cstring>
#include <sys/socket.h>#define SERVER_PORT 12345
#define SERVER_IP "127.0.0.1"
#define BUFFER_SIZE 1024int main() {int clientSocket = socket(AF_INET, SOCK_STREAM, 0);if (clientSocket == -1) {std::cerr << "Create socket failed!" << std::endl;return -1;}sockaddr_in serverAddr{};serverAddr.sin_family = AF_INET;serverAddr.sin_port = htons(SERVER_PORT);serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP);if (connect(clientSocket, reinterpret_cast<sockaddr*>(&serverAddr), sizeof(serverAddr)) == -1) {std::cerr << "Connect to server failed!" << std::endl;close(clientSocket);return -1;}std::cout << "Connected to server!" << std::endl;// Send messagestd::string message = "Hello from client!";send(clientSocket, message.c_str(), message.size(), 0);// Receive responsechar buffer[BUFFER_SIZE];ssize_t receivedBytes = recv(clientSocket, buffer, sizeof(buffer) - 1, 0);if (receivedBytes == -1) {std::cerr << "Receive failed!" << std::endl;} else if (receivedBytes == 0) {std::cerr << "Server closed connection!" << std::endl;} else {buffer[receivedBytes] = '\0';std::cout << "Received from server: " << buffer << std::endl;}close(clientSocket);return 0;
}

解释

  • TcpClient:客户端通过 connect()服务器建立连接,使用 send() 发送数据,并通过 recv() 接收服务器的响应。

3. 测试

1.编译:

g++ TcpServer.cpp -o TcpServer -std=c++17 -lpthread
  • 编译客户端
g++ TcpClient.cpp -o TcpClient -std=c++17

2.运行

./TcpServer
  • 启动客户端
./TcpClient

结语

通过这篇文章,我们实现了一个简单的 TCP 服务器和客户端示例,学习了如何使用 C++ 来进行网络编程。在实际项目中,你可以根据需求进一步扩展这些功能,比如加入多线程处理、客户端消息队列、认证机制等。


http://www.ppmy.cn/devtools/162722.html

相关文章

Docker Swarm 内置的集群编排

在现代容器化应用中&#xff0c;容器编排&#xff08;Container Orchestration&#xff09;是至关重要的&#xff0c;它负责自动化容器的部署、扩展、负载均衡和管理。Docker Swarm 是 Docker 提供的原生集群管理和容器编排工具&#xff0c;允许用户通过 Docker CLI 在多个 Doc…

UE5实现角色二段跳

1.二段跳 首先如果不想使用UE中增强输入功能&#xff0c;可以在SetupPlayerInputComponent函数中绑定对应的操作&#xff0c;具体可以自行查找。如果使用增强输入&#xff0c;可以通过创建一个UE自带的第三人称模板C项目学习&#xff0c;假设当前项目是创建自UE第三人称模板项目…

在windows下安装windows+Ubuntu16.04双系统(下)

这篇文章的内容主要来源于这篇文章&#xff0c;为正式安装windowsUbuntu16.04双系统部分。在正式安装前&#xff0c;若还没有进行前期准备工作&#xff08;1.分区2.制作启动u盘&#xff09;&#xff0c;见《在windows下安装windowsUbuntu16.04双系统(上)》 二、正式安装Ubuntu …

Windows、Mac、Linux,到底该怎么选?

在当今数字化时代&#xff0c;电脑已成为我们生活和工作中不可或缺的工具。而操作系统作为电脑的核心&#xff0c;其选择直接影响着我们的使用体验。Windows、Mac 和 Linux 作为三大主流操作系统&#xff0c;各自有着独特的优势和不足。今天&#xff0c;就来给大家详细分析一下…

如何使用Spring boot框架实现图书管理系统

使用 Spring Boot 框架实现图书管理系统可以按照以下步骤进行&#xff0c;涵盖了从项目搭建、数据库设计、后端接口开发到前端页面展示的整个流程。 1. 项目搭建 可以使用 Spring Initializr&#xff08;https://start.spring.io/ &#xff09;来快速创建一个 Spring Boot 项目…

Win11安装dpanel实现docker可视化面板,并解决端口冲突的问题

目标是给Win11的docker安装dpanel可视化面板&#xff0c;可以更直观的看到docker中的数据。 执行镜像&#xff08;没有则自动拉取&#xff09; 首先配置好docker加速环境&#xff08;阿里云的docker加速等&#xff09;&#xff0c;然后访问GitHub - donknap/dpanel: 轻量化 do…

054 redisson

文章目录 使用Redisson演示可重入锁读写锁信号量闭锁获取三级分类redisson分布式锁 package com.xd.cubemall.product.config;import org.redisson.Redisson; import org.redisson.api.RedissonClient; import org.redisson.config.Config; import org.springframework.context…

DeepSeek掘金——VSCode 接入DeepSeek V3大模型,附使用说明

VSCode 接入DeepSeek V3大模型,附使用说明 由于近期 DeepSeek 使用人数激增,服务器压力较大,官网已 暂停充值入口 ,且接口响应也开始不稳定,建议使用第三方部署的 DeepSeek,如 硅基流动 或者使用其他模型/插件,如 豆包免费AI插件 MarsCode、阿里免费AI插件 TONGYI Lin…