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

恼人的TCP套接字部分发送成功场景

源起

以前就知道套接字有可能出现部分发送成功的可能,直到近段时间一个典型的使用场景触发了明确的此问题,才予以重视,比较深入地考虑解决这个问题的方案!

分析

因为TCP的流式特征,如果出现部分发送成功,则剩余的部分数据也应该被发送出去,以利于对端正确处理消息。

如果抛弃了剩余部分,继续发送新的发送请求,则对端有可能无法正确处理,特别是解码带有边界特征的命令消息时,不能随便出现流中的间隙!

正确解决之道

  • 缓存剩余部分数据,在剩余部分未发送出去的情况下,明确拒绝下次发送请求,或设计一定的缓冲新发送请求的能力
  • 侦测TCP套接字的可写时机,实时发送剩余部分数据

注意,在TCP套接字重新可写,能够被write后,发送剩余部分,依然可能出现剩余

有局限性的对端缓解之道

在对于TCP流式传输的数据,特别在含有消息边界的业务中,TCP对端尝试多次后,依然无法解码数据,则可以采用抛弃已缓存读取数据的策略。

因为TCP命令消息输入不可能很频繁,在间歇报文信令间,抛弃脏数据,很有可能在后期处理就可以恢复正常 😃

多说几句

简单的网络套接字编程,在部分发送成功的处理上并不简单,比较耗代码!

参考

  • man 2 write

Such partial writes can occur for various reasons; for example, because there was insufficient space on the disk device
to write all of the requested bytes, or because a blocked write() to a socket, pipe, or similar was interrupted by a signal handler
after it had transferred some, but before it had transferred all of the requested bytes. In the event of a partial write, the
caller can make another write() call to transfer the remaining bytes. The subsequent call will either transfer further bytes or
may result in an error (e.g., if the disk is now full)

重点几个错误码可能部分发送成功的场景

  • EAGAIN
  • EWOULDBLOCK
  • EINTR

ACE框架下的解决之道

仅ACE_Message_Block组成的链表

利用ACE_Message_Block自身的链表能力,组成弹性的发送请求队列,然后从队头逐个处理发送请求,遇到部分发送成功,则修改当前发送ACE_Message_Block读指针rd_ptr(hasSendNum),并不从队列中删除。

ACE_Message_Queue

使用ACE_Message_Queue,依然可以形成弹性的发送请求队列,而且具备同步策略定制能力。需要在发送时,使用peek_dequeue_head接口,获取队头引用,但并不从链表中删除,发送完整成功后,再调用dequeue_head删除队头。

次之建议

ACE框架的TCP套接字提供了send_n接口,保证发送n个字节数据,或成功,或出现终态错误。

虽然接口看似简单,但是源码的解决办法还是有点ugly,建议在非常关键的心跳、握手场景中使用,并尽量不用之!

最次建议

使用同步阻塞IO,低效的同时,依然存在概率比较小,但仍然存在的中断情况下的部分发送成功 😦

结束语

解决思路的关键是保留宏观上的TCP流式数据特点,逐次发送,直至成功,或最终的失败,释放连接,并重新建链!

http://www.lryc.cn/news/179443.html

相关文章:

  • ROS2 中的轻量级、自动化、受控回放
  • Egg使用jwt拦截jtoken验证
  • 装饰器模式详解和实现(设计模式 二)
  • 面试问到MySQL模块划分与架构体系怎么办
  • 并查集及其优化
  • LeetCode 周赛上分之旅 #48 一道简单的树上动态规划问题
  • mysql报错:Column Count Doesn‘t Match Value Count at Row 1
  • 安卓 kuaishou 设备did和egid 学习分析
  • 基于Vue+ELement实现增删改查案例与表单验证(附源码)
  • webpack:使用externals配置来排除打包后的某个依赖插件IgnorePlugin的使用
  • 2023年中国工业脱水机行业供需分析:随着自动化和智能化技术的快速发展,销量同比增长4.9%[图]
  • [论文笔记]MacBERT
  • AI发展目前最大挑战是什么?
  • 自然语言处理NLP:LTP、SnowNLP、HanLP 常用NLP工具和库对比
  • 百度交易中台之内容分润结算系统架构浅析
  • 【索引】常见的索引、B+树结构、什么时候需要使用索引、优化索引方法、索引主要的数据结构、聚簇索引、二级索引、创建合适的索引等重点知识汇总
  • Egg 封装接口返回信息
  • Android AMS——创建APP进程(五)
  • 凉鞋的 Unity 笔记 102. 场景层次 与 GameObject 的增删改查
  • 信息安全:网络安全审计技术原理与应用.
  • 嵌入式Linux应用开发-第十三章APP怎么读取按键值
  • Web 中间件怎么玩?
  • HMTL知识点系列(4)
  • CFS内网穿透靶场实战
  • 【RabbitMQ实战】07 3分钟部署一个RabbitMQ集群
  • PS 切片工具 选择切片 切片存储
  • Git版本控制系统
  • Element UI搭建首页导航和左侧菜单以及Mock.js和(组件通信)总线的运用
  • What is an HTTP Flood DDoS attack?
  • 第 114 场 LeetCode 双周赛题解