@zhz:

疑问:有时候会看到某些代码,sendto()时用了while循环, 而recvfrom()时没使用while循环?

答:他们都可以使用循环语句,可参考TCP数据粘包的处理。

什么时候需要使用循环,什么时候不使用循环,可以看下面的分析:

以下其实是我根据自己项目使用的udp协议中的recvfrom()sendto()进行测试没问题后分析的。但是对于TCP粘包的问题,却并非如此,并非recv每次只取一次完整发送的数据(UDPrecvfrom()为什么可以取这么准?),我目前还没测试。
1. recvfrom()要使用与不使用循环的情况:

我们通常指定的接收端一次接收长度都会 >= 发送端一次发送的数据长度。通常情况下,我们发送端一次发送的数据长度都不会是固定的,所以就需要接收端设置一个合适的固定的接收长度,这个固定长度需要大于等于发送端一次发送的最大数据长度。

recvfrom()函数指定buf的长度后,并且一次recvfrom()函数读取到的数据小于指定长度max_length(这个是可以保证的),那么:

  • 如果能确定每次recvfrom()实际读取到的数据发送端一次发送的完整数据,那就不用循环recvfrom()
  • 如果每次recvfrom()实际读取到的数据不是发送端一次发送的完整数据,就需要循环recvfrom()

2.sendto()要使用与不使用循环的情况:

sendto()一般情况下需要使用循环,因为假如一个数据包太大,如长度为10MB,一次sendto()发送到输出缓冲区可能发不完整,此时就需要对sendto()使用循环发送,直到把10MB的数据都拷贝到输出缓冲区。
sendto()函数中参数指定的数据长度,就是本次发送(就是写入输出缓冲区)的数据长度,都会提前计算好之后再填入,每次发送的数据长短可能不一样,所以他就不是固定长度的。
recvfrom()函数中指定的长度是固定的。


3.recvfrom()sendto()例子:

recvfrom()sendto()的第三个参数len都是指定第二个参数buf的长度。

  • 1.recvfrom()从输入缓冲区中拷贝数据到应用程序缓冲区buf,在此需要指定buf的长度。他的长度一般在定义缓冲buf时就定下来了,如
constexpr std::size_t kBufferSize = 1024;
...
uint8_t buf[kBufferSize] = {0};  //定义buf时,长度也定下来了
std::memset(buf, 0, kBufferSize);
...
length = data_stream_->read(buf, kBufferSize, 0);
上面的read()函数会调用:
ret = ::recvfrom(sockfd_, buffer, kBufferSize, 0)
  • 2.sendto()从输出缓冲区中拷贝数据到应用程序缓冲区buf,在此需要指定buf的长度。他的长度都会提前计算好之后再填入,每次发送的数据长短可能不一样,所以他就不是固定长度的:
constexpr std::size_t kBufferSize = 1024;char buf[kBufferSize] = "abcd";
// proto_msg_是一个已经赋值后的protobuf消息的变量int proto_msg_length = proto_msg_.ByteSize();   // 把 proto_msg_ 序列化进buf,从buf第四字节开始,前四个字节为"cidi"proto_msg_.SerializeToArray(&buf[4], proto_msg_length);int send_size = proto_msg_length + 4;   // 加上"cidi"四个字节// 虽然 buf有1024字节,但是只将他的前 send_size 字节写入输出缓冲区std::size_t   len = data_stream_->write(reinterpret_cast<uint8_t*>(buf),send_size, 0);上面的write()函数会调用:
ret = ::sendto(sockfd_, buffer, kBufferSize, 0)


sendto()
size_t UdpStream::write(const uint8_t* data, size_t length, uint8_t flag) {size_t total_nsent = 0;// if (flag) {//   peer_sockaddr_.sin_addr.s_addr = htonl(INADDR_BROADCAST);// }peer_sockaddr_.sin_addr.s_addr = peer_addr_;peer_sockaddr_.sin_port = peer_broad_port_;SDEBUG << "sendto addr: " << inet_ntoa(peer_sockaddr_.sin_addr)<< ", port: " << ntohs(peer_sockaddr_.sin_port);while (length > 0) {ssize_t nsent =::sendto(sockfd_, data, length, 0, (struct sockaddr*)&peer_sockaddr_,(socklen_t)sizeof(peer_sockaddr_));if (nsent < 0) {  // errorif (errno == EINTR) {continue;} else {// errorif (errno == EPIPE || errno == ECONNRESET) {status_ = Stream::Status::DISCONNECTED;errno_ = errno;} else if (errno != EAGAIN) {status_ = Stream::Status::ERROR;errno_ = errno;}return total_nsent;}}total_nsent += nsent;length -= nsent;data += nsent;}return total_nsent;
}

recvfrom()
size_t UdpStream::read(uint8_t* buffer, size_t max_length, uint8_t flag) {ssize_t ret = 0;struct sockaddr_in addrfrom;addrfrom.sin_addr.s_addr = htonl(INADDR_ANY);if (flag) {peer_sockaddr_.sin_addr.s_addr = htonl(INADDR_ANY);} else {addrfrom.sin_addr.s_addr = peer_sockaddr_.sin_addr.s_addr;}while ((ret = ::recvfrom(sockfd_, buffer, max_length, 0,(struct sockaddr*)&peer_sockaddr_,reinterpret_cast<socklen_t*>(&socklenth_))) < 0) {if (errno == EINTR) {continue;} else {// errorif (errno != EAGAIN) {status_ = Stream::Status::ERROR;errno_ = errno;}}return 0;}// 接收来自本车obu的数据包:0x63,0x69,0x64,0x69分别表示cidi的ASCII码:99,105,100,105// 如果不是"cidi",1.如果是单播,就把ip保持为上一次成功单播的ip;// 2.如果是广播,就把ip设为0.0.0.0(即htonl(INADDR_ANY)),即本机任意网卡的ipif (0x63 != buffer[0] && 0x69 != buffer[1] &&0x64 != buffer[2] && 0x69 != buffer[3]) {peer_sockaddr_.sin_addr.s_addr = addrfrom.sin_addr.s_addr;}// // 0x60,0x61 分别对应'`'和'a'的ASCII码 96(`),97(a)// if (buffer[0] != 0x60 && buffer[1] != 0x61) {//   peer_sockaddr_.sin_addr.s_addr = addrfrom.sin_addr.s_addr;// }SDEBUG << "Receive addr: " << inet_ntoa(peer_sockaddr_.sin_addr)<< ", port: " << ntohs(peer_sockaddr_.sin_port);return ret;
}

【Socket网络编程】16.UDP 循环读取recvfrom() 与 循环发送 sendto()相关推荐

  1. Linux Kernel TCP/IP Stack — Socket Layer — TCP/UDP Socket 网络编程

    目录 文章目录 目录 TCP/UDP Socket 逻辑架构 创建 Socket 绑定 Socket 请求建立 Socket 连接 监听 Socket 接受请求 关闭连接 数据的发送和接收 send ...

  2. Day09: socket网络编程-OSI七层协议,tcp/udp套接字,tcp粘包问题,socketserver

    今日内容:socket网络编程     1.OSI七层协议     2.基于tcp协议的套接字通信     3.模拟ssh远程执行命令     4.tcp的粘包问题及解决方案     5.基于udp协 ...

  3. Python面向对象进阶和socket网络编程

    写在前面 为什么坚持?想一想当初: 一.面向对象进阶 - 1.反射补充 - 通过字符串去操作一个对象的属性,称之为反射: - 示例1: class Chinese:def __init__(self, ...

  4. 【socket】C语言的Socket网络编程

    目录 Socket网络编程 1.网络知识 网络中进程之间如何通信? 什么是Socket? socket一词的起源 怎么理解端口? 怎么理解socket ? 2. 客户/服务器模式 2.1 服务器端: ...

  5. C++socket网络编程大全实战http服务器(支持php)视频课程-夏曹俊-专题视频课程

    C++socket网络编程大全实战http服务器(支持php)视频课程-16782人已学习 课程介绍         C++socket网络编程大全实战http服务器(支持php)视频培训教程概况:本 ...

  6. 1.socket网络编程

    socket网络编程总结(Linux+Windows) 理解为:套接字通信,网络通信 1.概念 1.1 局域网和广域网 局域网:局域网将一定区域内的各种计算机.外部设备和数据库连接起来形成计算机通信的 ...

  7. 【Linux网络编程】UDP 套接字编程

    [Linux网络编程]UDP 套接字编程 [1]用户数据报协议(UDP) UDP是一个简单的传输层协议,不保证UDP数据报会到达其最终目的地,不保证各个数据报的先后顺序跨网络后保持不变,也不保证每个数 ...

  8. 视频教程-C++socket网络编程--http服务器(支持php)实战教学视频-C/C++

    C++socket网络编程--http服务器(支持php)实战教学视频 夏曹俊:南京捷帝科技有限公司创始人,南京大学计算机硕士毕业,有15年c++跨平台项目研发的经验,领导开发过大量的c++虚拟仿真, ...

  9. Linux 网络编程——socket 网络编程

    文章目录 一.网络基础 TCP/UDP对比 TCP/IP协议族体系 socket IP地址 IP地址转化API inet_addr() inet_aton() inet_ntoa() inet_pto ...

最新文章

  1. 输入vue ui没反应
  2. python自定义线程
  3. ​​​​​​​CV:利用cv2(加载人脸识别xml文件及detectMultiScale函数得到人脸列表)+keras的load_model(加载表情hdf5、性别hdf5)并标注
  4. nrf51822-主从通信分析2
  5. ABAP--通过LDB_PROCESS函数使用逻辑数据库
  6. python中common是什么意思_common中的python无效语法
  7. Shell(1)——执行脚本
  8. Js获取字符串的显示宽度/高度
  9. 网络采集库NCrawler
  10. stm32 通用bootloader_stm32最简单的实现BootLoader
  11. (十二)Linux内核驱动之poll和select
  12. mysql存过游标_mysql存储过程 游标 循环使用介绍
  13. 软考:软件设计师(历年真题汇总)|希赛网
  14. SQL注入了解认识及注入方式
  15. 深度学习之跟学霹雳吧啦Wz笔记
  16. 记录一下unity3d资源加载Resources.Load资源加载的坑
  17. Windows下运行python脚本报错“ImportError: No Module named ...”的解决方法
  18. CPU核心数目 与 多线程
  19. VB中对EXCEL的各种操作
  20. 换一个地方也许国产WPS OFFICE 会重夺办公软件霸主!

热门文章

  1. 机器学习算法与Python实践之(二)支持向量机
  2. JS中map()与forEach()的用法
  3. 点一万个赞:商汤SiamRPN目标跟踪最强算法开源
  4. 美国进入“非结构化”数据分析新时代
  5. 计网 - HTTP 协议_强制缓存和协商缓存的区别
  6. Oracle启动和停止的方式详解
  7. clockdiff-检测两台linux主机的时间差
  8. 数据结构-单链表(C语言代码)
  9. mysql查询时给字段加内容,mysql数据库查询之对应库对应表中的注释信息查询以及加字段查询...
  10. ik mysql热加载分词_Elasticsearch 之(25)重写IK分词器源码来基于mysql热更新词库...