网络编程
网络分层
疑问
为什么需要分层?
网络传输流程比较复杂,涉及到传输稳定,安全性加密等等等等进程通信的网络版?
是的,进程间通信在同一个计算机,没有什么外部影响,而网络会有各种各样的苛刻条件
意义:
- 将一个非常复杂的过程分部,更效率地解决
学习重点:
- 站在应用层,学习传输层的基础协议TCP/UDP和他们给用户层提供的接口的使用。
网络编程的一些元素
套接字 socket 插座
意义
- 理解为一个端点,和文件描述符号一样,是一个句柄,提供数据交互的一个口
sockaddr_in
意义
- 专门用来放ipv4地址和端口的结构体,而且是网络端序,无法直接用%s或者%d读取
套接字端点在希望与别人连接时,就应该要有一个sockaddr和他绑定,无论是为了连接别人(使用发送接口)还是暴露自己(使用接收接口)。
端口号
意义:
- 提供精确到进程的点对点网络通信
除了1023个系统端口(没有注册权限)
和注册端口(尽量不要使用)
还有可以使用的49151~65535端口,而且同一个端口可以让两种协议同时使用,不冲突。
字节序
意义:
- 提高跨平台能力,网络统一大端序
哪些内容需要转换大端序,哪些不用
- 以一个字节为单位的数据不用转换,比如字符,包括字符数组(字符串)
- 以多个字节为单位的数据需要转换,包括端口号,IP地址,int,short等等
典例:
- 端口号:端口号转为网络字节后,再放到一个无符号短整型,如sockaddr_in.sin_port中,最后的s如果换成l表示无符号长整型,端口号使用s即可
1 | //本地转网络 |
- IP地址,由于IP地址表示时是字符串,和端口号不一样
1 | //本地字符串转换为网络字节 |
UDP和TCP
UDP (user datagram protocol)
意义:
- 提供一种方便快速的传输,但是顺序和完整性不保证
典例:
- 小尺寸数据,DNS查询域名IP地址
- 需要实时性但不严格完整性,流媒体
- 更适合一对多,有自带的广播机制
过程:
- 接收方
- 创建一个套接字,通信的端点
- 将一个sockaddr与这个端点绑定,暴露自己的信息,给别人连
- 使用接口recvfrom与这个端点内部相连,读取端点来的数据
- 发送方
- 创建一个套接字,通信的端点
- 提供需要连接端点绑定的sockaddr,才知道信息发到哪里
- 使用接口sendto与这个端点内部相连,将数据搜到端点去
TCP (Transmission Control Protocol)
意义:
- 提供一个不易丢失数据的连接方式,副作用是连接麻烦,占资源多
使用:
- 传输的内容远远大于连接的占用资源
- 需要严格保证数据完整性的情况
过程:
- 接收方,创建socket、绑定bind(IP等)、设为监听listen、阻塞等待连接accept、读写数据(通过上一步返回的socket号)、断开
- 发送方,创建socke、(不绑定)直接连接对方connect(对方IP)、读写数据、断开
细节:
- 传输过程出现了3个套接字,分别是服务端的监听套接字,建立连接收发信息的套接字,客户端收发信息的套接字。connect套接字都是由一个监听套接字产生的
- connect三次握手也是阻塞的,如果对方没有回复,将阻塞,超时会失败
- 如何判断对方离线,释放网络套接字的必然时机?当调用recv时,如果离线,马上返回零,此时是绝对的释放时机。
三次握手
意义
- 建立一个可靠的、全双工的连接,确保客户端和服务器双方都确认对方的接收能力。
过程
- 客户端向服务器发送一个SYN报文,包含一个初始序列号Seq=A(第一次握手)。
- 服务器收到SYN报文后,发送一个SYN-ACK报文,包含服务器的初始序列号Seq=B,并确认收到客户端的序列号Ack=A+1(第二次握手)。
- 客户端收到SYN-ACK后,发送一个ACK报文,确认服务器的序列号Ack=B+1,并通知服务器可以开始数据传输(第三次握手)。
安全性体现:
- 伪造IP的客户端无法完成三次握手,因为它无法接收到服务器返回的SYN-ACK报文(其中包含的Seq=B和Ack=A+1),这些报文被路由到真正的IP地址。因此,伪造IP的客户端无法建立连接。
UDP和TCP的对比
从步骤上来说,UDP作为接收方时,少了设置监听和将等待连接和接收合成一步
UDP作为发送方时,将连接和发送合成一步
网络编程中的一些ioctl
意义
- 提供了获取本地网络信息的接口
1 | //获取某个网口的ip内容 |
- 还有一些常用获取地址信息方式
getsockname( ) 获得本端套接字的地址信息
getpeername( ) 获得对端套接字的地址信息
gethostbyname( ) 根据主机名取得主机信息
一些经典模型
单线程设置非阻塞轮询
意义:
- 一个简单的非阻塞模型
缺点很明显,让CPU利用率达到百分之百。
信号驱动模型
意义:
给UDP提供了异步信号处理机制,提高工作效率同时无需多线程处理也能达到并发
缺点:
如果UDP信号并发数量过大,可能丢失信号
信号模式让参数传递变得麻烦,可能不适合带参的情况,需要使用全局变量
结论:
信号驱动模型比较适合较轻量级,UDP,不需要传递参数到服务函数的情况
select 多路复用
意义:
- 无需使用多线程,又可以接受多个套接字的任务,达到高并发,一种非常节省资源效率又高效的模型,TCP可用
疑问:
- 哪些套接字放在读就绪,哪些放在写就绪?
- 希望接收消息的套接字放在读就绪
- 网络套接字也是放在读就绪,可以监控握手和挥手请求
- 一般写就绪状态被阻塞的情况是缓冲区满,消息堆积的情况,正常情况下不会阻塞写就绪
过程
- 声明一个客户端套接字数组,全部清零
- 开始无限循环
- 清空监听集,将数组中的所有非零套接字和监听套接字放到读监听集中,并且更新套接字最大值
- 设置监听,参数1:最大套接字+1,参数234:套接字集地址,NULL
- 监听套接字响应方式设为将新得到的客户端套接字放入数组,并更新套接字最大值
- 遍历非零套接字响应方式为接受消息返回消息等自定义操作,(客户端发送消息和断开连接都会触发套接字可读)根据接受消息的返回值可区分是否断开连接
详细
- 多路复用利用了内核的事件通知机制,不需要进行轮询也能一直监控所有套接字的变化,非常高效省资源。
缺点
- 对于需要消耗较多时间的连接,会阻塞其他连接,毕竟是单线程,因此只适合快连接快断开的情况。
指数补偿
设置一个阈值,越等越久,直到达到阈值# 超时控制
意义
超时控制
意义
- 提供一个更加精确的网络阻塞控制方案
详细
- TCP和UDP都有超时属性,有连接超时和读取数据超时
步骤
1.使用signal和alarm设置超时控制
TCP粘包问题
疑问
- 粘包为什么会出现?
因为TCP发送是有缓冲机制的,多条小消息可能会合成一条长消息发送,而接受方会一次接到一条长消息,从而粘包。
解决方案
- 1.通过分割符(类似JSON)发送,接收端能够识别消息
- 2.消息长度前缀,先读取消息长度再根据长度读取内容(HTTP)
- 3.约定固定长度(使用结构化数据)
- 4.分段发送,先发OK,这边收到确认,再发下一段数据
OneNet云平台
Cjson
疑问
- json数据不是都一样吗?为什么要分出一个Cjson,C的json和java的json难道不一样?
意义
- 提供了C中可以使用的json库,对嵌入式设备优化更好
注意
- 在json中,有键值对和对象两个概念,对象object是需要创建节点的,而键值对只需要add函数添加
- 对象嵌套键是一个键不是一个对象,不需要创建节点
- 数组健是一个键,不需要创建对象,但是数组元素是对象,需要创建节点
HTTP
意义
- 提供了更完善的传输协议
特点
- HTTP是将 TCP/IP协议封装的应用层的协议
- 无连接无状态,每次请求与响应无关联
请求报文
- 请求行:请求方法 URL 协议版本\r\n
- 请求头:头部字段:值\r\n
- \r\n
- 请求包体(一般为空)
响应报文
- 状态行:协议版本 状态码 状态码描述\r\n
- 响应头:头部字段:值\r\n
- \r\n
- 响应包体:数据块
- 响应包体:2a\r\n数据块\r\n4ad\r\n数据块\r\n (分块发送的情况)
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.



