欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > Linux Socket TCP处理粘包问题

Linux Socket TCP处理粘包问题

2024/10/24 12:23:03 来源:https://blog.csdn.net/qq_37923517/article/details/140846720  浏览:    关键词:Linux Socket TCP处理粘包问题

  TCP协议由于有组合发包机制(多个send语句中的字节合并到一个包中),会出现粘包问题。

  下面例子中客户端不停给服务器发送8000个'0'接8000个'1',服务器需要不断接收并检查字节流是否满足这个格式。

客户端代码

/* client.c */
#include <stdio.h>
#include <stdlib.h>
//#include <string.h>
#include <cstring>
#include <strings.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>#define BUFFER_SIZE (20000)
#define CLIENT_SUCCESS (0)
#define CLIENT_FAILURE (-1)
#define MAX_PENDDING_QUEUE (10)char client_buf[BUFFER_SIZE] = {0}; static void client_usage(void)
{printf("#####################################\n");printf("#Client Usage:                      #\n");printf("#gcc client.c -o client             #\n");printf("#chmod 777 client                   #\n");printf("#./client <ip> <port>               #\n");printf("#                                   #\n");printf("#<ip>:server ip:192.168.xx.xx       #\n");printf("#<port>:server port:1024~65535      #\n");printf("#####################################\n");return;
}int main(int argc, char *argv[])
{int sockfd = -1;int ret;int recv_bytes;struct sockaddr_in serveraddr;if (argc < 3) {client_usage();return CLIENT_FAILURE;}socklen_t serveraddrLen = sizeof(serveraddr);/* socket */sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd == -1) {printf("[ERROR]client socket failed, why:%s\n", strerror(errno));return CLIENT_FAILURE;}printf("[DEBUG]client socket success, sockfd = %d\n", sockfd);/* serveraddr */memset(&serveraddr, 0x00, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));inet_pton(AF_INET, argv[1], &serveraddr.sin_addr);ret = connect(sockfd, (const struct sockaddr *)&serveraddr, sizeof(serveraddr));if (ret == -1) {printf("[ERROR]client connect failed, why:%s\n", strerror(errno));close(sockfd);return CLIENT_FAILURE;}printf("[DEBUG]client connect success\n");for(size_t i=0; i<40; ++i){/*printf("\033[1m---> \033[0m"), fflush(stdout);fgets(client_buf, sizeof(client_buf), stdin);printf("\n");if (strncmp(client_buf, "quit!", strlen("quit!")) == 0) {printf("[DEBUG]client said %s\n", client_buf);break;}
*/std::memset(client_buf, '0', 8000);std::memset(client_buf + 8000, '1', 8000);send(sockfd, client_buf, 16000, 0);//       sleep(1);}close(sockfd);printf("[DEBUG]<=====client exit\n");return CLIENT_SUCCESS;
}

服务器代码,处理粘包方式之一就是循环读取(见下面Force_Recv函数),直到获得指定长度的字节。


#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>//using namespace std;#define BUFFER_SIZE (20000)
#define IP_SIZE (100)
#define SERVER_SUCCESS (0)
#define SERVER_FAILURE (-1)
#define MAX_PENDDING_QUEUE (10)char server_buf[BUFFER_SIZE] = {0};
//char combine_buf[BUFFER_SIZE] = {0};static void server_usage(void)
{printf("#####################################\n");printf("#Server Usage:                      #\n");printf("#gcc server.c -o server             #\n");printf("#chmod 777 server                   #\n");printf("#./server <ip> <port>               #\n");printf("#                                   #\n");printf("#<ip>:server ip:192.168.xx.xx       #\n");printf("#<port>:server port:1024~65535      #\n");printf("#####################################\n");return;
}inline bool check(char *ch)
{size_t i = 0;for(; i<8000; ++i)if(ch[i] != '0'){printf("Check at %u : %x\n", i, ch[i]);return false;}for(; i<16000; ++i)if(ch[i] != '1'){printf("Check at %u : %x\n", i, ch[i]);return false;}return true;
}inline int Force_Recv(int sockfd, char buf[], size_t len, int flags)
{size_t offset = 0;while(offset < len){size_t recv_bytes = recv(sockfd, buf + offset, len - offset, flags);if (recv_bytes <= 0) {return recv_bytes;}offset += recv_bytes;}return len;
}int main(int argc, char *argv[])
{int listenfd = -1;int connectfd = -1;int ret;int recv_bytes;struct sockaddr_in serveraddr;struct sockaddr_in clientaddr;socklen_t peerlen;char client_addr[IP_SIZE] = {0};if (argc < 3) {server_usage();return SERVER_FAILURE;}socklen_t clientAddrLen = sizeof(clientaddr);/* socket */listenfd = socket(AF_INET, SOCK_STREAM, 0);if (listenfd == -1) {printf("[ERROR]server socket failed, why:%s\n", strerror(errno));return SERVER_FAILURE;}printf("[DEBUG]server socket success, listenfd = %d\n", listenfd);/* serveraddr */memset(&serveraddr, 0x00, sizeof(serveraddr));serveraddr.sin_family = AF_INET;serveraddr.sin_port = htons(atoi(argv[2]));inet_pton(AF_INET, argv[1], &serveraddr.sin_addr);/* bind */ret = bind(listenfd, (const struct sockaddr *)&serveraddr, sizeof(serveraddr));if (ret != 0) {printf("[ERROR]server bind failed, why:%s\n", strerror(errno));close(listenfd);return SERVER_FAILURE;}printf("[DEBUG]server bind success\n");/* listen */ret = listen(listenfd, MAX_PENDDING_QUEUE);if (ret != 0) {printf("[ERROR]server listen failed, why:%s\n", strerror(errno));close(listenfd);return SERVER_FAILURE;}printf("[DEBUG]server listen success\n");printf("server waiting for connect......\n\n");/* accept */while (true) {memset(&clientaddr, 0x00, sizeof(clientaddr));peerlen = sizeof(clientaddr);connectfd = accept(listenfd, (struct sockaddr *)&clientaddr, &peerlen);if (connectfd == -1) {printf("[ERROR]server accept failed, why:%s\n", strerror(errno));close(listenfd);return SERVER_FAILURE;}memset(client_addr, 0x00, sizeof(client_addr));inet_ntop(AF_INET, &clientaddr.sin_addr, client_addr, sizeof(client_addr));printf("[DEBUG]server connected, client ip:%s, port:%d\n\n", client_addr, ntohs(clientaddr.sin_port));/* send and recv */size_t times = 0;while (true) {printf("\033[1m<--- \033[0m");memset(server_buf, 0x00, sizeof(server_buf));recv_bytes = Force_Recv(connectfd, server_buf, 16000, 0);if (recv_bytes == -1) {printf("[ERROR]server recv failed, why:%s\n", strerror(errno));close(connectfd);close(listenfd);return SERVER_FAILURE;} else if (recv_bytes == 0) {printf("[DEBUG]server detected client gone!\n");close(connectfd);return SERVER_SUCCESS;}++times;if(!check(server_buf))printf("%u time, wrong\n", times);elseprintf("%u time, success\n", times);//printf("client@%s:%d said:%s\n", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port), server_buf);//printf("\033[1m---> \033[0m"), fflush(stdout);//fgets(server_buf, sizeof(server_buf), stdin);//send(connectfd, server_buf, sizeof(server_buf), 0);}}close(listenfd);return SERVER_SUCCESS;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com