- 一、网络协议 UDP
- UDP用户数据报协议:传输层
- 网络编程模型
- B/S模型:browser/server(浏览器/服务器)
- 客户端是通用的客户端(浏览器)
- 一般只做服务器开发
- 客户端要加载的数据均来自服务器
- C/S模型:client/server(客户端/服务端)
- 客户端是一个专用的客户端
- 服务器和客户端都需要开发
- 客户端可保存资源,本地加载,无需所有数据都请求服务器
- UDP编程流程
- 套接字:文件描述符(网络通信时,应用层可操作的端口)
- 发送端
- socket:int socket(int domain, int type, int protocol
- 功能:创建通信的套接字
- 参数:
- domain:网络层使用什么协议族
- AF_INET: IPv4
- AF_INET6:IPv6
- type:规定传输层的协议
- SOCK_DGRAM:UDP协议
- SOCKSTREAM:TCP协议
- SOCKRAW:原始套接字
- protocol:0 按照默认协议方式创建
- 返回值:成功:套接字;失败:-1
- sendto:ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen)
- 功能:向网络套接字发送数据
- 参数:sockfd:套接字;buf:要发送的数据的首地址;len:要发送的字节数;flags:0:按照默认方式发送;dest_addr:接收方的地址信息(IP+端口号);addrlen:接收方地址的大小
- man 7 ip

- 返回值:成功:实际发送的字节数;失败:-1
- 网络字节序:大段
- 主机字节序:小段
- uint3 2_t htonl(uint32_t hostlong);主机转网络
- uint1 6_t htons(uint16_t hostshort);主机转网络
- uint3 2_t ntohl(uint32_t hostlong);网络转主机
- uint1 6_t ntohs(uint16_t hostshort);网络转主机
- in_addr_t inet _addr(const char *cp);
- char *inet _ntoa(struct in_addr in);

- 接收端
- bind:int bind(int sockfd, const struct sockaddr *addr.socklen_t addrlen);
- 功能:绑定自己的IP地址和端口号
- 参数:sockfd:套接字;addr:需要绑定的地址;adlrlen:地址大小
- 返回值:成功:0;失败:-1
- recvfrom:ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen)
- 功能:从套接字上接收数据
- 参数:sockfd:套接字;buf:存放接收数据的内存首地址;len:希望接收的字节数;flags:0:按照默认方式接收(阻塞);src_addr:发送方的地址信息;addrlen:发送发地址的指针
- 返回值:成功:实际接收到的字节数;失败:-1

- UDP特点
- 面向数据包
- 无需建立连接
- 尽最大努力交付,不安全、不可靠(数据丢包、乱序)
- 可实现一对一、一对多的传输
- 机制简单,资源开销小,数据传输实时性高(VNC、直播)
- 如何避免UDP丢包
- 发送方以较慢的速度发送数据,让接收端有足够的时间处理数据
- 模仿TCP的机制:应答机制
- 抓包工具 wireshark
- 网络抓包:抓取通过设备网卡的网络数据,从而调试和分析网络程序
- 使用:
- sudo wireshark启动抓包工具
- 选取要抓取的网卡---》any
- 选择一个过滤条件
- 开始抓取
- 进行一次网络通信
- UDP报文头部 共8字节

- 源端口号:发送方网络进程端口号
- 目标端口号:接收方网络进程端口号
- 长度:UDP发送的报文的整体长度(UDP头部
- 二、网络协议 TCP
- TCP特点
- 面向数据流
- 有链接(通信之前必须建立链接)
- 安全可靠的传输机制
- 机制复杂、网络资源开销大
- 本质只能实现一对一的通信(使用TCP并发方式可实现一对多通信)
- TCP三次握手和四次挥手机制
- 三次握手
- TCP建立连接时,需要进行三次握手,为了确保收发双方通信之前都已准备就绪

- SYN:请求建立链接标志位
- ACK:相应报文标志位
- 四次挥手
- TCP断开连接时,需要进行四次挥手,确保断开连接前双方都已通信结束

- FIN:请求断开连接标志位
- ACK:相应报文标志位
- 服务端在发送ACK、FIN之间依然可以传输数据
- TCP的编程流程
- 发送端
- connect :int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
- 功能:请求与服务端建立连接
- 参数:sockfd:套接字;addr:要连接的服务端的地址信息;addrleqn:服务端地址大小
- 返回值:成功:0;失败:-1
- send :ssize_t send(int sockfd, const void *buf, size_t len, int flags)
- 功能:发送网络数据
- 参数:sockfd:网络套接字;buf:要发送的数据首地址;len:发送的字节数;flags:0:按照默认方式发送
- 返回值:成功:实际发送的字节数;失败:-1

- 接收端
- listen :int listen(int sockfd, int backlog);
- 功能:监听建立三次握手的客户端
- 参数:sockfd:监听套接字;backlog:最大允许监听的客户端个数
- 返回值:成功:0;失败:-1
- accept :int accept(int socket, struct sockaddr *restrict address,socklen_t *restrict address_len);
- 功能:接收建立三次握手的客户端,并产生一个通讯套接字
- 参数:socket:监听套接字;address:客户端的地址信息;addresslen:客户端地址长的指针
- 返回值:成功:通讯套接字;失败:-1
- recv :ssize _t recv(int sockfd, void *buf, size_t len, int flags);
- 功能:从网络套接字上接收数据
- 参数:sockfd:通讯套接字;buf:存放接收数据的首地址;len:期望接收到的字节数;flag:0:默认方式接收(阻塞)
- 返回值:成功:实际接收到的字节数;失败:-1;对方断开连接时:0

- TCP粘包问题
- 发送方应用层发送的多包数据,将来在接收方可能一次读到,多包数据产生了粘连
- 原因:
- 发送方速度较快,TCP底层可能对多包数据进行重新组帧
- 接收方数据处理速度较慢,导致多包数据在接收缓冲区缓存,应用层读时,一次将多包数据读出
- 解决方法
- 调整发送速率
- 发送指定大小,接收方接收指定大小(结构体)
- 应用层为发送的数据增加分隔符,利用分隔符解析
- 封装自定义数据帧格式进行发送(协议)
