ZBLOG

TCP粘包 c++ 实例

下面是一个使用 C++ 实现的简单 TCP 粘包示例,包括服务器端和客户端代码。此示例将演示如何在 TCP 连接中发生粘包,并展示如何处理这个问题。

TCP 服务器端

#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>

#define PORT 12345
#define BUFFER_SIZE 1024

void start_server() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    
    // 创建 socket
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }
    
    // 强制绑定到端口
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    // 绑定 socket
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 开始监听
    if (listen(server_fd, 3) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    std::cout << "Server is listening on port " << PORT << std::endl;

    while (true) {
        // 接受连接
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
                                 (socklen_t*)&addrlen))<0) {
            perror("accept");
            exit(EXIT_FAILURE);
        }

        char buffer[BUFFER_SIZE] = {0};
        
        // 接收数据,假设每次接收1024个字节
        ssize_t bytes_received = recv(new_socket, buffer, BUFFER_SIZE - 1, 0);
        
        if (bytes_received > 0) {
            buffer[bytes_received] = '\0'; // 确保字符串结束
            std::cout << "Received: " << buffer << std::endl; 
            // 注意:如果发生了粘包,这里可能会接收到多个消息的合并。
            /*
              示例输出可能为:
              Received: Message 1Message 2Message ...
             */
            
            // 分割并处理逻辑可以在这里实现。
            for(int i=0; i<bytes_received; ++i){
                if(buffer[i] == '\n'){ 
                    std::cout << "End of message detected." << std::endl;
                }
            }
            
            // 向客户端发送响应(可选)
            const char* response = "Message received\n";
            send(new_socket, response, strlen(response), 0);
        }

        close(new_socket); 
   }
}

int main() {
   start_server();
   return 0;
}

TCP 客户端

#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <unistd.h>

#define SERVER_IP "127.0.0.1"
#define PORT 12345

void send_data() {
   int sock = 0;
   struct sockaddr_in serv_addr;

   // 创建 socket 文件描述符
   if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
       std::cout << "\n Socket creation error \n";
       return;
   }

   serv_addr.sin_family = AF_INET;
   serv_addr.sin_port = htons(PORT);

   // 将 IPv4 地址从文本转化为二进制形式
   if(inet_pton(AF_INET, SERVER_IP, &serv_addr.sin_addr)<=0) {
       std::cout << "\nInvalid address/ Address not supported \n";
       return;
   }

   // 尝试连接到服务器
   if (connect(sock, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0) {
       std::cout << "\nConnection Failed \n";
       return;
   }

   // 模拟发送多个小消息,每个消息以换行符结尾
   for (int i = 1; i <=10; ++i) {
       std::string message = "Message " + std::to_string(i) + "\n";
       send(sock , message.c_str(), message.length(), MSG_NOSIGNAL);
       usleep(100000); // 添加一些延迟,以增加粘包的可能性 
   }

   close(sock);
}

int main() {
     send_data();
     return 0;
}

编译与运行

  1. 编译服务器
g++ server.cpp -o server -lpthread 
  1. 编译客户端
g++ client.cpp -o client 
  1. 先启动服务器
./server 
  1. 然后启动客户端
./client 

输出结果分析

  • 在运行时,你会看到服务器打印出接收到的信息。如果发生了粘包,输出可能会是一长串信息,比如 Received: Message xMessage y...

  • 如果你希望避免粘包,可以在每条消息前加上固定长度的头部或使用分隔符(如换行符),并在服务器解析这些数据时进行相应处理。

总结

通过以上代码,我们创建了一个简单的TCP客户端和服务端来演示粘包现象。在真实的应用场景中,你需要更复杂的数据解析逻辑来处理这些情况。希望这个例子能帮助你理解TCP粘包的概念!如果有其他问题,请告诉我!


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:http://sdn.0voice.com/?id=5494

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?