1 如何收取数据?

对于收数据,当接受连接成功得到 clientfd 后,我们会将该 clientfd 绑定到相应的 IO 复用函数上并监听其可读事件。当可读事件触发后,调用 recv 函数从 clientfd 上收取数据(这里不考虑出错的情况),根据不同的网络模式我们可能会收取部分或一次性收完。收取到的数据我们会放入接收缓冲区内,然后做解包操作。对于使用 epoll 的 LT 模式(水平触发模式),我们每次可以只收取部分数据;但是对于 ET 模式(边缘触发模式),我们必须将本次收到的数据全部收完。

  • ET 模式收完的标志是 recv 或者 read 函数的返回值是 -1,错误码是 EAGAIN。

linux进行非阻塞的socket接收数据时会出现Resource temporarily unavailable,errno代码为11(EAGAIN),表明你在非阻塞模式下调用了阻塞操作,在该操作没有完成就返回这个错误,这个错误不会破坏socket的同步,不用管它,下次循环接着recv就可以。

2 如何发送数据?

对于发数据,除了 epoll 模型的 ET 模式外,epoll 的 LT 模式或者其他 IO 复用函数,我们通常都不会去注册监听该 clientfd 的可写事件。这是因为,只要对端正常收数据,一般不会出现 TCP 窗口太小导致 send 或 write 函数无法写的问题。因此大多数情况下,clientfd 都是可写的,如果注册了可写事件,会导致一直触发可写事件,而此时不一定有数据需要发送。故而,如果有数据要发送一般都是调用 send 或者 write 函数直接发送,如果发送过程中, send 函数返回 -1,并且错误码是EAGAIN 表明由于 TCP 窗口太小数据已经无法写入时,而仍然还剩下部分数据未发送,此时我们才注册监听可写事件,并将剩余的服务存入自定义的发送缓冲区中,等可写事件触发后再接着将发送缓冲区中剩余的数据发送出去,如果仍然有部分数据不能发出去,继续注册可写事件,当已经无数据需要发送时应该立即移除对可写事件的监听。这是目前主流网络库的做法。

直接尝试发送消息处理逻辑:

/***@param data 待发送的数据*@param len  待发送数据长度*/
void TcpConnection::sendMessage(const void* data, size_t len)
{    int32_t nwrote = 0;size_t remaining = len;bool faultError = false;if (state_ == kDisconnected){LOGW("disconnected, give up writing");return;}// 当前未监听可写事件,且发送缓冲区中没有遗留数据if (!channel_->isWriting() && outputBuffer_.readableBytes() == 0){//直接发送数据nwrote = sockets::write(channel_->fd(), data, len);      if (nwrote >= 0){remaining = len - nwrote;           }else // nwrote < 0{nwrote = 0;//错误码不等于EWOULDBLOCK说明发送出错了if (errno != EWOULDBLOCK){LOGSYSE("TcpConnection::sendInLoop");if (errno == EPIPE || errno == ECONNRESET){faultError = true;}}}}//发送未出错且还有剩余字节未发出去if (!faultError && remaining > 0){//将剩余部分加入发送缓冲区outputBuffer_.append(static_cast<const char*>(data) + nwrote, remaining);if (!channel_->isWriting()){//注册可写事件channel_->enableWriting();}}
}

不能全部发出去监听可写事件后,可写事件触发后处理逻辑:

//可写事件触发后会调用handleWrite()函数
void TcpConnection::handleWrite()
{  //将发送缓冲区中的数据发送出去int32_t n = sockets::write(channel_->fd(), outputBuffer_.peek(), outputBuffer_.readableBytes());if (n > 0){//发送多少从发送缓冲区移除多少outputBuffer_.retrieve(n);//如果发送缓冲区中已经没有剩余,则移除监听可写事件if (outputBuffer_.readableBytes() == 0){//移除监听可写事件channel_->disableWriting();if (state_ == kDisconnecting){shutdown();}}}else{//发数据出错处理LOGSYSE("TcpConnection::handleWrite");           handleClose();}
}

LT和ET模式需要注意如下问题:

  • epoll LT 模式:注册监听一次可写事件后,可写事件触发后,尝试发送数据,如果数据此时还不能全部发送完,不用再次注册可写事件;
  • epoll  ET 模式:注册监听可写事件后,可写事件触发后,尝试发送数据,如果数据此时还不能全部发送完,需要再次注册可写事件以便让可写事件下次再次触发(给予再次发数据的机会);

网络协议收发数据问题相关推荐

  1. Linux网络协议:当eBPF遇上Linux内核网络 | Linux内核之旅

    <直播预告 | 当eBPF遇见Linux内核网络> 哔哩哔哩:https://www.bilibili.com/video/BV1ch411U75f?from=search&sei ...

  2. arp协议的主要功能是_程序员需要掌握的一些网络协议汇总

    今天我们来看下各层的网络协议,虽然开发过程中写代码不会直接涉及,但是理解好网络协议对编程和理解系统的整个运行过程是非常有帮助的哦. 一.应用层协议 1.HTTP HTTP(HyperText Tran ...

  3. 【网络协议从入门到底层原理】【00】课程大纲_互联网与网络协议

    持续学习&持续更新中- 学习态度:守破离 [网络协议从入门到底层原理][00]课程大纲_互联网与网络协议 课程大纲 互联网(Internet) 为什么要学习网络协议 基本常识 C/C++的跨平 ...

  4. android udp 收发例子_网络协议之TCP和UDP

    首先强调一点,TCP/IP协议是一个协议簇.里面包括很多协议的,UDP只是其中的一个, 之所以命名为TCP/IP协议,因为TCP.IP协议是两个很重要的协议,就用他两命名了. 两个协议的区别实际使用时 ...

  5. linux网络编程:使用多进程实现socket同时收发数据

    转载:http://blog.csdn.net/li_wen01/article/details/52685844 前面已讲过使用一个进程实现服务端和客户端P2P通信的实例,但是它只能同时处理一个客户 ...

  6. java服务器tcpip协议,Java 实现TCP/IP协议的收发数据(服务端)

    功能如下: 注: 只有服务端,没有客户端,测试时采用第三方软件作为客户端的. 收发数据目前能正常收发数据,只是中文的会变成乱码显示. 采用Thread类实现一个收发数据的线程. 服务端代码: impo ...

  7. 网络协议分层_接口测试之网络分层和数据

    网络分层和数据 上一小节中介绍了接口测试中一些必要重要的定义,这一节我们来讨论一下在学习接口测试过程中我们要关注的最重要的东西:网络分层和数据. 首先,我们来尝试理解一下,为什么网络是要分层的呢? 我 ...

  8. Wireshark数据抓包分析(网络协议篇)1.2安装Wireshark

    Wireshark数据抓包分析(网络协议篇)1.2安装Wireshark Wireshark(前称Ethereal)是一个网络包分析工具.该工具主要是用来捕获网络包,并显示包的详细情况.本节将分别介绍 ...

  9. Wireshark数据抓包分析(网络协议篇)第1章网络协议抓包概述

    Wireshark数据抓包分析(网络协议篇)第1章网络协议抓包概述 网络协议是用于不同计算机之间进行网络通信的.网络协议是网络上所有设备(如网络服务器.计算机.交换机.路由器等)之间通信规则的集合,它 ...

最新文章

  1. Bootstrap常用类
  2. vue实现上下滑动翻页_vue 实现滚动到底部翻页效果(pc端)
  3. 51 SD配置-定价配置-维护定价过程
  4. Android 系统(257)---Launcher显示未读通知的数量
  5. docker如何进入后台容器
  6. 联想K3全系,救黑砖(只要手机链接电脑有端口识别就能恢复正常)
  7. windows系统的启动工作原理
  8. JPL星历文件de405下载方法
  9. 微信小程序的测试方案总结
  10. 图解机器学习算法(8) | 回归树模型详解(机器学习通关指南·完结)
  11. android nef转jpg格式文件,nef格式转换成jpg
  12. java开发 微信商家转账到零钱,发起商家转账API,微信支付
  13. 谈如何归纳和分类美术风格比较合理
  14. 创作swing 绝对布局 窗口事件 鼠标事件 键盘事件 上传头像流程
  15. PAT考试大纲/如何刷pat(想要在pat甲级拿80到90分)
  16. hive hue 中文乱码的问题
  17. 本周内外盘行情回顾2022.3.6
  18. 美团技术岗扩招,年薪最高近40万。你有能力进美团吗?
  19. owasp_我的Google夏天的owasp 2020代码之旅
  20. 一个数如果恰好等于它的因子之和,这个数就称为 完数 。例如6=1+2+3.编程 找出1000以内的所有完数。

热门文章

  1. 二维平面坐标系中,判断某点是否在正六边形内 | python 实现 + 数学推导(已知正六边形六个顶点坐标)
  2. mysql的权限管理
  3. 易语言远程查询oracle数据库连接,易语言如何连接远程服务器上的数据库,并读取数据...
  4. php使用函数封装去除空格,去除php注释和去除空格函数分享_PHP教程
  5. java io异常处理_IO流异常处理
  6. FZU 2169 shadow (用了一次邻接表存边,树形DP)
  7. 关于网站注册账号时提示Server 对象 错误 'ASP 0177 : 800401f3'
  8. listview选中高亮
  9. 头文件malloc.h:函数 mallopt()的选项
  10. 2015-11-19 转载 DPDK支持的网卡类型