首页 > 代码库 > udp编程的学习
udp编程的学习
最近在做一个网络应用小程序(虽然很烦应用层编程。。。),实现视频数据通过网络无限发送,不关有无网络,数据都发出,用于产品的老化测试。
起初代码是用TCP写的,TCP有连接,产品作为server,起一个监控connect线程,有client连接,监控线程告诉主线程,主线程就将数据发出,没有client连接,主线程则将数据抛空。
但是有这样一个需求,用户插入网线后,PC端的client接收数据,然后强制拔掉网线,这时server还要一直在发送数据(数据是发出还是抛空无所谓),这样实现产品的长时间运行老化。
起初我想模拟这种现象,就在client代码中connect后接收一小段数据就return,直接结束client。
发现server会受到SIG_PIPE退出,所以就屏蔽掉SIG_PIPE信号。这样可以实现client突然结束后server只是write错误返回,还可以继续无限的write。
但是后来真正的来操作拔插网线的时候发现,现象不是这样的!
server的write client的read会阻塞在那。
这样产品端的server就阻塞,不能达到老化的效果啊。
后来网上查阅TCP的协议,发现应该是TCP的握手信号导致这个问题,TCP是传输控制协议,协议内会保证数据的正确性,所以每次的数据发送都会等待接收端的ACK。
而被动退出(拔掉网线),接收端根本没有回复,server端就会反复发送之前没有ACK 的数据,导致write阻塞。
所以一定要注意被动退出和主动退出的差别啊!
TCP达不到想要的效果,考虑用UDP来实现这个功能。
UDP是数据包协议,不保证数据正确传输,它仅仅是对IP协议进行了简单的封装(增加了端口),所以要保证数据传输的正确性需要程序员自己来处理。
UDP相对于TCP的一个好处就是没有建立连接时的开销,这样两个端点之间没有就必要维持连接,这样也就不需要单开线程来监控连接啦。
因此UDP特点是速度快,易丢包,很适合于视频 音频的网络传输(这里要传输的数据就是视频)。
将TCP代码改为UDP,因为不知道用户的IP,但UDP的sendto函数需要指定目标地址,因此想到的解决办法是向该局域网内的广播地址发送,client也从该广播地址接收。
UDP编程的基础知识有空也需要整理一下!
广播数据包的原理:
专门用于同时向网络中所有工作站进行发送的一个地址叫做广播地址。
在使用TCP/IP 协议的网络中,主机标识段host ID 为全1 的IP 地址为广播地址。
如果你的IP为:192.168.1.39,子网掩码为:255.255.255.0,则广播地址为:192.168.1.255;如果IP为192.168.1.39,子网掩码为:255.255.255.192,则广播地址为:192.168.1.63。
如果只想在本网络内广播数据,只要向广播地址发送数据包即可,这种数据包可以被路由,它会经由路由器到达本网段内的所有主机,此种广播也叫直接广播;
如果想在整个网络中广播数据,要向255.255.255.255发送数据包,这种数据包不会被路由,它只能到达本物理网络中的所有主机,此种广播叫有限广播。
使用UDP协议发送、接收广播包的过程。
假如我们要向192.168.0.X,子网掩码为:255.255.255.0的子网中发送广播包。
发送端server操作步骤如下:
1.使用socket函数 创建SOCK_DGRAM类型的Socket。
2 bind绑定本机的ip以及port
3. setsockopt设置Socket的属性允许其广播。
4. 无限循环发送数据包到192.168.0.255(指定port)
接收端client操作步骤如下:
1使用socket函数创建SOCK_DGRAM类型的SOCKET。
2 使用bind函数绑定192.168.0.255以及port
3 recvfrom接收数据。
4. 关闭Socket
注意事项如下:
1. 接收方一定要知道广播地址以及广播端口号,然后绑定此广播地址以及端口号才能正确接收。
2. 接收方的Socket不需要设置成广播属性。
实际使用中发现udp单次接收的包大小一定等于发送端单次包大小。
udp包大小最好能在到达底层链路层时小于等于MTU,也就是保证udp数据包不被ip层分片,因为udp可能丢数据,被ip层分片发出后在接收端就有在ip层数据包组装出错的问题。
udp编程的学习