多机TCP通讯之hello world(C++)

文章目录

TCP是什么

TCP(传输控制协议)是一种在计算机网络中广泛使用的协议,它提供了可靠的、面向连接的数据传输服务。TCP 是 OSI 模型中的传输层协议,它确保了数据的可靠性、顺序性和流控制。

以下是 TCP 通讯的一些关键特点和概念:

  • 可靠性: TCP 提供可靠的数据传输。它使用确认机制,确保数据的每个部分都已被成功接收,如果数据在传输中出现错误或丢失,TCP 将负责重新传输。

  • 面向连接: TCP 是一种面向连接的协议。在进行数据传输之前,必须先建立连接。连接的建立和终止都需要一些握手和挥手的过程,以确保双方都已准备好进行通信。

  • 全双工通信: TCP 支持全双工通信,即双方可以同时发送和接收数据。这使得双方能够在同一时间内进行双向的通信。

  • 流控制: TCP 使用窗口控制机制来进行流量控制。这确保了在通信双方之间合适的速率上进行数据传输,防止发送方发送过多数据导致接收方无法处理。

  • 顺序性: TCP 保证传输的数据按照发送的顺序到达接收端。即使在网络中出现乱序的情况,TCP 会重新排序数据,以确保按照正确的顺序进行处理。

  • 连接管理: TCP 提供连接的建立、维护和释放。连接的建立和释放过程中包含握手和挥手的步骤,以确保通信的可靠性和一致性。

  • 端口和套接字: 在 TCP 通信中,通信的双方通过端口和套接字进行标识。端口用于标识特定的应用程序,而套接字则表示在网络中的通信端点。

  • 可靠的错误检测和重传机制: TCP 使用序号和确认号来确保数据的可靠传输。如果发送方没有收到确认,它将会重新发送数据。

总体而言,TCP 是一种适用于可靠、有序、面向连接的数据传输的协议。它适用于需要确保数据完整性的应用场景,如文件传输、网页浏览、电子邮件等。然而,由于其一些额外的开销和复杂性,对于一些实时性要求较高的应用,可能会选择使用UDP等协议。

准备工作

  • 打开防火墙: sudo ufw enable
  • 打开目标端口:例如打开22端口sudo ufw allow 22
  • 测试前,ping一下,看连接是或否成功。

两端的通讯流程

CMakeLists.txt

cpp 复制代码
cmake_minimum_required(VERSION 3.18)
project(ExampleProgram)

set(CMAKE_CXX_STANDARD 11)


add_executable(tcp-client tcp-client.cpp)
add_executable(tcp-server tcp-server.cpp)


# Add -lpthread
target_link_libraries(tcp-client pthread)
target_link_libraries(tcp-server pthread)

服务端代码

cpp 复制代码
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int main() {
    // 创建服务器套接字
    int serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    if (serverSocket == -1) {
        std::cerr << "Failed to create server socket." << std::endl;
        return 1;
    }

    // 设置服务器地址结构
    sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_addr.s_addr = INADDR_ANY;
    serverAddr.sin_port = htons(8080); // 服务器监听的端口号

    // 绑定套接字
    if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
        std::cerr << "Bind failed." << std::endl;
        close(serverSocket);
        return 1;
    }

    // 监听连接
    if (listen(serverSocket, SOMAXCONN) == -1) {
        std::cerr << "Listen failed." << std::endl;
        close(serverSocket);
        return 1;
    }

    std::cout << "Server is listening for incoming connections..." << std::endl;

    while (true) {
        // 接受连接
        int clientSocket = accept(serverSocket, NULL, NULL);
        if (clientSocket == -1) {
            std::cerr << "Accept failed." << std::endl;
            close(serverSocket);
            return 1;
        }

        std::cout << "Connection established with a client." << std::endl;

        // 发送消息给客户端
        const char* message = "Hello from server!";
        if (send(clientSocket, message, strlen(message), 0) == -1) {
            std::cerr << "Error sending message." << std::endl;
        }

        // 关闭客户端套接字
        close(clientSocket);
    }

    // 服务器永远不会执行到这里,但可以加上关闭服务器套接字的代码
    close(serverSocket);

    return 0;
}

客户端代码

cpp 复制代码
#include <iostream>
#include <cstring>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

int main() {
    while (true) {
        // 创建客户端套接字
        int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
        if (clientSocket == -1) {
            std::cerr << "Failed to create client socket." << std::endl;
            return 1;
        }

        // 设置服务器地址结构
        sockaddr_in serverAddr;
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_addr.s_addr = inet_addr("192.168.110.83"); // 服务器的 IP 地址
        serverAddr.sin_port = htons(8080); // 服务器监听的端口号

        // 连接到服务器
        if (connect(clientSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == -1) {
            std::cerr << "Connection failed." << std::endl;
            close(clientSocket);
            return 1;
        }

        std::cout << "Connected to the server." << std::endl;

        // 接收消息
        char buffer[256];
        memset(buffer, 0, sizeof(buffer));
        if (recv(clientSocket, buffer, sizeof(buffer), 0) == -1) {
            std::cerr << "Error receiving message." << std::endl;
        } else {
            std::cout << "Received message from server: " << buffer << std::endl;
        }

        // 关闭客户端套接字
        close(clientSocket);

        // 在这里可以添加一些延时,以避免过于频繁地连接服务器
        sleep(1);
    }

    return 0;
}

参考

https://blog.csdn.net/cyj_001/article/details/131782022
https://www.bilibili.com/video/BV1ne411A7hP/?spm_id_from=333.337.search-card.all.click&vd_source=667c3d14dbb51ec849c0bc7c38329d10

相关推荐
cherub.5 分钟前
深入解析信号量:定义与环形队列生产消费模型剖析
linux·c++
暮色_年华20 分钟前
Modern Effective C++item 9:优先考虑别名声明而非typedef
c++
重生之我是数学王子28 分钟前
QT基础 编码问题 定时器 事件 绘图事件 keyPressEvent QT5.12.3环境 C++实现
开发语言·c++·qt
Koi慢热32 分钟前
路由基础(全)
linux·网络·网络协议·安全
我们的五年1 小时前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
做人不要太理性1 小时前
【C++】深入哈希表核心:从改造到封装,解锁 unordered_set 与 unordered_map 的终极奥义!
c++·哈希算法·散列表·unordered_map·unordered_set
程序员-King.1 小时前
2、桥接模式
c++·桥接模式
chnming19872 小时前
STL关联式容器之map
开发语言·c++
程序伍六七2 小时前
day16
开发语言·c++
小陈phd2 小时前
Vscode LinuxC++环境配置
linux·c++·vscode