客户端偶现没有收到服务器响应问题的排查

  • 问题描述
  • 问题排查
  • 总结

问题描述

客户端偶现收不到服务器端返回的响应包。

问题排查

当出现服务器端收不到客户端的请求包,或者客户端收不到服务器端的响应包时,第一反应就是是抓包,先确定是否存在丢包的可能。
输入命令:tcpdump -i eth0 src port 9983 -XX抓取我们服务器9983端口发出去的包,结果如下:
     其中红色圈出来的部分就是应该返回的响应包,确定服务器端没有丢包。同样的,使用wireshark抓来自服务器端的包,结果如下:

     客户端也收到了服务端的包,到此基本排除丢包的可能。

这个时候我同时也注意到了XWGetKpacgRSp这个响应包是和上一个响应包未发完的部分作为一个完整包发送的。上一个响应包大小是2720字节:
     当前包大小是527字节:

     因此推测是不是客户端处理拆包的流程有问题,贴上客户端处理拆包的代码:

for (;;){//初始化为0,分配四分之一的READ_BUF_SIZE大小,约为32768字节uint32_t free_buf_len = m_in_buf.GetAllocSize() - m_in_buf.GetWriteOffset();if (free_buf_len < READ_BUF_SIZE)m_in_buf.Extend(READ_BUF_SIZE);int ret = netlib_recv(m_handle, m_in_buf.GetBuffer() + m_in_buf.GetWriteOffset(), READ_BUF_SIZE);if (ret <= 0) break;//write_offset偏移当前已经接收的字节数m_in_buf.IncWriteOffset(ret);//做最小长度保护while (m_in_buf.GetWriteOffset() >= imcore::HEADER_LENGTH){//比如接收到了472+55字节//其中472字节和前面的27200是一起的,且length=27668//第一次取出来的是上面netlib_recv返回的长度uint32_t len = m_in_buf.GetWriteOffset();uint32_t length = 0;//获取包体长度memcpy(&length, m_in_buf.GetBuffer(), sizeof(length));length = ntohl(length);//len:接收的总长度//length:包体长度//PACK_HEADER_LENGTH:包体长度的长度//PACK_HEADER_LENGTH + length <= len : 才可以解析//如果字符串长度大于此次接收的长度,那么不处理,等待下一次if (length + PACK_HEADER_LENGTH > len)break;try{if (m_pTcpSocketCB)m_pTcpSocketCB->onReceiveData((const char*)m_in_buf.GetBuffer(), length + PACK_HEADER_LENGTH);LOGBIN_F__(SOCK, "OnRead", m_in_buf.GetBuffer(), length + PACK_HEADER_LENGTH);}catch (std::exception& ex){assert(FALSE);LOGA__(NET, "std::exception,info:%s", ex.what());if (m_pTcpSocketCB)m_pTcpSocketCB->onReceiveError();}catch (...){assert(FALSE);LOG__(NET, _T("unknown exception"));if (m_pTcpSocketCB)m_pTcpSocketCB->onReceiveError();}//已经读取的长度置为已读m_in_buf.Read(NULL, len);}}

XWGetKpacgRSp上一个响应包的大小为4+27668字节,每次发送2720字节,总共发送了10次,最后一个包527字节。也即最后一个网络包包含了55字节大小的XWGetKpacgRSp响应包(因为TCP协议是流模式的)。
     那么在这段代码中,需要判断包体长度和接收长度的大小,如果接收长度小于包体长度,那么不做处理,继续接收,直到接收长度大于等于包体长度。最后将接收到的长度置为已读,避免下次再读:

//已经读取的长度置为已读
m_in_buf.Read(NULL, len);

可是这里置为已读的长度是当前接收缓存中的未读内容的总长度(也就是上面的2720*10+527),也就是将55字节大小的XWGetKpacgRSp响应包合并到了上一个响应包,这样就导致拆包失败,客户端没有再对XWGetKpacgRSp响应包做处理。将代码修改如下解决问题:

//已经读取的长度置为已读
m_in_buf.Read(NULL, length + PACK_HEADER_LENGTH);

总结

客户端对服务端的数据包进行处理时,需要考虑粘包问题,这一点大家都知道,那么在书写代码的时候就需要格外小心,避免因为低级的代码书写错误导致程序功能异常。
     当出现客户端与服务器端收不到对方的请求或响应时,按照以下流程排查问题:
1,抓包。分别抓客户端和服务端的网络数据包,看数据是否发送出去或者接收到。(TCP协议是可靠的,不存在丢包问题)
2,如果服务端没有发出响应包,则排查服务端的发包流程是否正常。
3,如果服务端有发出数据包,客户端也有收到,那么排查客户端的收包流程是否正常,特别是粘包,拆包的处理。

客户端偶现没有收到服务器响应问题的排查相关推荐

  1. 谷歌邮箱服务器验证失败,Gmail错误:SMTP服务器需要安全连接,或者客户端未经身份验证。服务器响应为...

    Gmail错误:SMTP服务器需要安全连接,或者客户端未经身份验证.服务器响应为 我使用以下代码发送电子邮件.代码在我的本地机器中正确工作.但是在生产服务器上,我得到了错误消息.var fromAdd ...

  2. 服务器流式响应,HttpClient在收到服务器响应后无法停止流式传输

    我一直在使用.NET 4.5中的HttpClient挣扎了一段时间.在通过分块传输对WebApi端点进行大型流式上传时,如果服务器已通过非成功状态代码(未找到,认证,授权,验证错误等)响应中间请求,则 ...

  3. inode客户端未收到服务器响应,iNode认证通过后提示“未收到服务器相应,即将强制下线的解决办法”...

    iNode认证提示服务器无响应 一,问题描述 使用iNode客户端进行portal或者8021x认证,身份认证通过后过了十几秒,iNode提示"未收到服务器相应,即将强制下线",然 ...

  4. 东方梦符祭未能收到服务器响应,东方梦符祭loading不进去 常见问题解决办法

    最近东方梦符祭更新之后不少玩家反应出现Loading进不去游戏的情况,遇到这样的问题,大家可以参考以下的解决方法. 推荐阅读[东方梦符祭新手N1 进阶攻略 东方梦符祭要怎么玩] >>> ...

  5. 并发请求多 服务器响应慢 post,【转】吞吐量、QPS(TPS)、并发数、RT性能指标及ab并发测试...

    概念 吞吐量 系统的吞吐量是指系统的抗压.负载能力,指的是单位时间内处理的请求数量.通常情况下,吞吐率用 "字节数/秒" 来衡量,也可以用 "请求数/秒",&q ...

  6. 服务器响应回调函数,解决有关flask-socketio中服务端和客户端回调函数callback参数的问题(全网最全)...

    由于工作当中需要用的flask_socketio,所以自己学习了一下如何使用,查阅了有关文档,当看到回调函数callback的时候,发现文档里都描述的不太清楚,最后终于琢磨出来了,分享给有需要的朋友 ...

  7. 网页现现实理服务器没有响应,前端_网页编程 HTTP协议(进阶)

    文章目录 内容 1. HTTP协议简介 1.1 什么是通信 1.1.1 现实生活中的通信 1.1.2 互联网中的通信 1.2 什么是通信协议 1.2.1 现实生活中的通信协议 1.2.2 互联网中的通 ...

  8. 服务器响应到客户端中文乱码的解决方式

    服务器与客户端交互的过程中出现中文乱码的解决方式 服务器响应到客户端中文乱码的解决方式 在Java Web开发的过程中,很多人都会遇到当服务器向浏览器发送响应页面时,有时候因为码表的查询不一致,会在浏 ...

  9. inode显示未收到服务器回应,inode智能客户端 未收到服务器回应

    inode智能客户端 未收到服务器回应 内容精选 换一换 华为云帮助中心,为用户提供产品简介.价格说明.购买指南.用户指南.API参考.最佳实践.常见问题.视频帮助等技术文档,帮助您快速上手使用华为云 ...

最新文章

  1. R语言dplyr包if_else条件判断选择函数实战
  2. 多行文本框限制输入字符长度(两种方法)
  3. iOS Sprite Kit教程之xcode安装以及苹果帐号绑定
  4. data中的数据如何在innerhtml中调用_Vuex中调用state数据
  5. batocera游戏整合包_星露谷物语绅士mod整合包
  6. 使用DynamoDBMapper扫描DynamoDB项目
  7. 不使用Ajax,如何实现表单提交不刷新页面
  8. vue按钮Button
  9. Go 远超 Python,机器学习人才极度稀缺,全球 16,655 位程序员告诉你这些真相!...
  10. 家装计算器php,家装计算器
  11. [转载] python数字类型(一)
  12. 读写分离无效的大坑(新使用数据库读写分离的同学可以参考)
  13. 贝叶斯(Bayes)决策理论
  14. MacBook重装系统
  15. python实现CRAPS赌博游戏。
  16. b站《史上最全unity3D教程》2-6等ppt笔记3
  17. UiPath估值超百亿!这家来自罗马尼亚深耕中国市场的公司已进入市场高增长期...
  18. 课程linux实验报告,Linux课程综合训练实验报告
  19. 部门换届推文文字_毕业季,换届忙
  20. mp3剪切器如何剪切mp3格式的音频

热门文章

  1. Epicor中的时间格式转换 - How to convert time from string to time format
  2. 我看《谍影重重1、2》
  3. 契约机器人插件分享CS系列-短网址生成
  4. SEO专业培训教程:网站title与meta中7个标点符号的正确使用
  5. 【181225】VC++窗口化的奇迹修改程序源代码
  6. 今天小鱼搬家,简单说说Gazebo
  7. 抛物样条曲线(最详细简单的解析)
  8. zulutrade外汇自动跟单系统介绍
  9. 极客头条 | 5月14日科技要闻:百度贴吧 2017 前贴子无法访问;网易腾讯游戏获批;苹果反垄断案败诉
  10. 简单的检索式问答系统