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

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;
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 实现基于 Python 和 xterm.js 的 Web 交互终端demo
  • 掌控情绪,驾驭人生,在人生的漫长旅程中,情绪如同多变的天气,时而风和日丽,时而狂风骤雨
  • pypinyin,一个有趣的 Python 库!
  • 关于qt中如何布局
  • c++ - 模拟实现set、map
  • vscode启动不了的问题解决
  • 5 mysql 查询语句
  • Java中等题-多数元素2(力扣)【摩尔投票升级版】
  • 黑暗之魂和艾尔登法环有什么联系吗 黑暗之魂和艾尔登法环哪一个好玩 苹果电脑怎么玩Windows游戏 apple电脑可以玩游戏吗
  • TCP 和 UDP 之间的区别?
  • 「阅读」数据密集型系统设计第三章
  • 电子元器件—电容和电感(一篇文章搞懂电路中的电容和电感)(笔记)(面试考试必备知识点)电容和电感作用、用途、使用、注意事项、特点等(面试必备)-笔记(详解)
  • 第三关:Git 基础知识
  • 【Python】异常处理及程序调试
  • 记录一次环境的安装
  • Android Volley源码解析
  • hadoop集群管理系统搭建规划说明
  • Java 内存分配及垃圾回收机制初探
  • Odoo domain写法及运用
  • Otto开发初探——微服务依赖管理新利器
  • PAT A1120
  • Python - 闭包Closure
  • React Native移动开发实战-3-实现页面间的数据传递
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • Spring核心 Bean的高级装配
  • Sublime Text 2/3 绑定Eclipse快捷键
  • v-if和v-for连用出现的问题
  • Vue2.x学习三:事件处理生命周期钩子
  • VuePress 静态网站生成
  • vue总结
  • 爱情 北京女病人
  • 对话:中国为什么有前途/ 写给中国的经济学
  • 设计模式(12)迭代器模式(讲解+应用)
  • - 转 Ext2.0 form使用实例
  • PostgreSQL 快速给指定表每个字段创建索引 - 1
  • 东超科技获得千万级Pre-A轮融资,投资方为中科创星 ...
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • ​十个常见的 Python 脚本 (详细介绍 + 代码举例)
  • (1)(1.13) SiK无线电高级配置(六)
  • (10)ATF MMU转换表
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (四)c52学习之旅-流水LED灯
  • (转)Linux下编译安装log4cxx
  • (转)Scala的“=”符号简介
  • (转)socket Aio demo
  • .halo勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复
  • .NET C# 操作Neo4j图数据库
  • .NET C# 配置 Options
  • .NET WebClient 类下载部分文件会错误?可能是解压缩的锅
  • .net反编译的九款神器
  • .NET设计模式(7):创建型模式专题总结(Creational Pattern)
  • @Autowired注解的实现原理
  • @data注解_一枚 架构师 也不会用的Lombok注解,相见恨晚
  • [ 转载 ] SharePoint 资料
  • [5] CUDA线程调用与存储器架构