Linux系统编程——网络协议
UDP
UDP:传输层,用户数据报协议
网络编程模型
B/S模型:browser/server(浏览器/服务器)
1,客户端为公用的客户端(浏览器)
2,一般只做服务器开发
3,客户端要加载的数据均来自服务器
C/S模型:client/server(客户端/服务端)
1,客户端是一个专用的客户端
2,服务器和客户端都需开发
3,客户端可保存资源,本地加载,无需所有数据都请求服务器
UDP特点
1,面向数据包
2,无需建立连接
3,尽最大努力交付,因此不安全不可靠,因为可能造成数据丢包、乱序(发送方发送太快,对于接收方来说数据处理能力跟不上,导致大量的数据在缓冲区积攒,缓冲区满时数据便丢失)
4,可实现一对一、一对多的传输
5,时效性高,资源开销小,机制简单,数据实时性高(例如VNC、直播)
如何避免UDP丢包
1,发送方以较慢的速度发送数据,接收方又有足够的时间处理数据
2,模仿TCP机制:应答机制
网络抓包
网络抓包:抓取通过数倍网卡的网络数据,从而调试和分析网络程序
抓包工具:wireshark
使用:
1,启动抓包工具:sudo wireshark
2,选取要抓取的网卡----any(所有)
3,选取一个过滤条件
4,开始抓取
5,进行网络通信
UDP报文头部分为四个字段
1,源端口号(2字节):发送方进程的端口号
2,目标端口号(2字节):接收方进程的端口号
3,长度(2字节):UDP发送的报文的整体长度,包括UDP头部(总共8字节)和UDP正文部分
4,校验和(2字节):数据差错校验
UDP编程流程
套接字:文件描述符,是网络通信时应用层可操作的端口
socket
功能:创建通信的套接字
参数:
domin:网络层使用什么地址协议族
AF_INET:IPv4
AF_INET6:IPv6
type:规定传输层的协议
SOCK_DGRAM : UDP协议
SOCK_STREAM:TCP协议
SOCK_RAW :原始套接字
protocol:0为按照默认协议方式创建
返回值:成功则为套接字,失败则为-1
sendto
功能:向网络套接字发送数据
参数:
sockfd:套接字
buf:要发送的数据的首地址
len:要发送的字节数
flags:0为按照默认方式发送
dest_addr:接收方的地址信息(IP + 端口号)
man 7 ip
参数要求const struct sockaddr *,直接使用强转即可
sin_family:地址协议族
sin_port:端口号,必须是网络字节序(大端)由于主机字节序是小端,所以需要进行转化,由函数htons
sin_addr:IP地址,与端口号同理,需要转网络字节序,即inet_addr
addrlen:接收方的地址大小
返回值:成功则为实际发送的字节数,失败则为-1
例:
bind
功能:绑定自己的IP地址和端口号
参数:
sockfd:套接字
addr:需要绑定的地址
addrlen:地址大小
返回值:成功则0失败-1
recvfrom
功能:从套接字上接收数据
参数:
sockfd:套接字
buf:存放接收数据的内存首地址
len:希望接收的字节数
flags:0为按照默认阻塞方式回收
src_addr:发送方的地址信息,提前定义变量来存,如果不关注为NULL
addrlen:发送方地址的指针,如果不关注为NULL
返回值:成功则为实际收到的字节数,失败则为-1
TCP
TCP特点
1,面向数据流
2,通信之前必须建立链接
3,安全可靠的传输机制
4,机制复杂,网络资源开销大
5,本质只能实现一对一的通信(使用TCP并发方式可以实现一对多)
TCP三次握手和四次挥手机制
三次握手:TCP建立连接时,需要进行三次握手,为了确保收发双方通信之前都已准备就绪
客户端会向服务端发送一包数据,这包数据里有一个明显的标志位SYN(请求建立联系标),服务端接收到之后,会给对方回应一个ACK(响应报文标志位)和SYN,最后客户端再回ACK,谁先发都行
四次挥手:TCP断开连接时。需要进行四次挥手,确保断开连接前双方都已通信结束
谁先发FIN都行,而后发的ACK和FIN不能像三次握手一样同时发,因为接收到客户端FIN并给予ACK回应时,并不代表服务端也要断开连接,如果同时发就表示同时断开连接
TCP编程流程
服务端,在创建监听套接字sockfd之后,调用listen时,listen会在后台创建两个队列,负责保存待完成三次握手的客户端(A)和已完成三次握手的客户端(B),若有客户端请求建立连接但未完全建立连接,则该客户端信息会保存在A中,再来客户端就继续保存,当有客户端已完全建立连接,则该客户端信息则会出队,被保存在B中
connect
功能:请求与服务端建立连接
参数:
sockfd:套接字
addr:要连接的服务端地址信息
addrlen:服务端地址大小
返回值:成功则0失败-1
send
功能:发送网络数据
参数:
sockfd:网络套接字
buf:要发送的数据首地址
len:发送的字节数
flags:0则按照默认方式发送
返回值:成功则为实际发送的字节数,失败则为-1
listen
功能:监听建立三次握手的客户端
参数:
sockfd:监听套接字
backlog:最大允许监听的客户端个数
返回值:成功则0失败-1
accept
功能:接收建立三次握手的客户端,并产生一个通讯套接字
参数:
sockfd:监听套接字
address:已完成三次握手的客户端的地址信息,需自己定义
address_len:客户端地址长度的指针
返回值:成功则为通讯套接字,失败则为-1
recv
功能:从套接字上接收数据
参数:
sockfd:通讯套接字
buf:存放接收数据的首地址
len:期望接收到的字节数
flag:0则为默认方式
返回值:成功则为实际接到的字节数,失败-1。如果对方断开连接则为0
TCP存在的问题——粘包问题
发送方应用层发送的多包数据,将来在接收方可能一次读到,多包数据产生了粘连
造成问题的原因:
1. 发送方速度较快,TCP底层可能对多包数据进行重新组帧
2. 接收方数据处理速度较慢,导致多包数据在接收缓冲区缓存,应用层读时,一次将多包数据读出
解决方法:
1,调整发送速率
2.,发送指定大小,接收方也指定大小,例如结构体
注意:如果是跨平台之间的数据传输,需要注意结构体对齐问题,比如32bits平台和64位bit平台
3,应用层为发送的数据增加分隔符\n,利用分隔符解析
4,封装自定义数据帧格式进行发送(协议),严格根据协议进行解析
例:十六进制
AA C0 00 00 00 F0 00 BB 10 A0 00 00 00 10 校验 BB
帧头:AA len,上例C0为数据的长度,为了防止同时出现与帧尾帧头相同的数据
帧尾:BB
有效数据长度:C0
有效数据:00 00 00 F0 00 BB 10 A0 00 00 00 10
校验:8位和校验;16位和校验;CRC校验:为了验证数据传送过程中是否出现问题
以8位和校验为例,从帧头开(或者有效数据)始后一个字节,一直加到校验之前的数据,一个字节一个字节的加起来,得到的数的第八个bit作为校验和