Socket是基于传输层TCP、UDP协议封装的一套API接口,它本身并不是一种协议。
网络通信模型
传输层中的协议
传输控制协议 (TCP)
TCP全称是Transmission Control Protocol,中文名为传输控制协议,它可以提供可靠的、面向连接的网络数据传递服务。
传输控制协议主要包含下列任务和功能:
确保IP数据报的成功传递
对程序发送的大块数据进行分段和重组
确保正确排序及按顺序传递分段的数据
通过计算校验和,进行传输数据的完整性检查
根据数据是否接收成功发送肯定消息。通过使用选择性确认,也对没有收到的数据发送否定确认
TCP工作流程
TCP的连接建立过程又称为TCP三次握手
一旦初始的三次握手完成,client和server就可以相互发送信息。
而断开连接时,就不分client和server了,先请求断开的即为主动方,主动方会先发送断开请求,被动发在收到断开请求后会先给主动方一个确认,然后待被动方处理完所有的传输事务后,再给主动方一个断开连接的请求,
主动方收到被动方的断开请求,给被动方一个断开确认。至此断开成功。
TCP工作过程比较复杂,包括的内容如下:
TCP连接关闭:发送方主机和目的主机建立TCP连接并完成数据传输后,会发送一个将结束标记置1的数据包,以关闭这个TCP连接,并同时释放该连接占用的缓冲区空间。
TCP重置:TCP允许在传输的过程中突然中断连接。
TCP数据排序和确认*:在传输的过程中使用序列号和确认号来跟踪数据的接收情况。
TCP重传:在TCP的传输过程中,如果在重传超时时间内没有收到接收方主机对某数据包的确认回复,发送方主机就认为此数据包丢失,并再次发送这个数据包给接收方。
TCP延迟确认:TCP并不总是在接收到数据后立即对其进行确认,它允许主机在接收数据的同时发送自己的确认信息给对方。
TCP数据保护(校验):TCP是可靠传输的协议,它提供校验和计算来实现数据在传输过程中的完整性。
tcp报文格式
源端口、目标端口:计算机上的进程要和其他进程通信是要通过计算机端口的,而一个计算机端口某个时刻只能被一个进程占用,所以通过指定源端口和目标端口,就可以知道是哪两个进程需要通信。源端口、目标端口是用16位表示的,可推算计算机的端口个数为2^16个。
序列号:表示本报文段所发送数据的第一个字节的编号。在TCP连接中所传送的字节流的每一个字节都会按顺序编号。由于序列号由32位表示,所以每2^32个字节,就会出现序列号回绕,再次从 0 开始。那如何区分两个相同序列号的不同TCP报文段就是一个问题了,后面会有答案,暂时可以不管。
确认号:表示接收方期望收到发送方下一个报文段的第一个字节数据的编号。也就是告诉发送发:我希望你(指发送方)下次发送的数据的第一个字节数据的编号是这个确认号。也就是告诉发送方:我希望你(指发送方)下次发送给我的TCP报文段的序列号字段的值是这个确认号。
TCP首部长度:由于TCP首部包含一个长度可变的选项部分,所以需要这么一个值来指定这个TCP报文段到底有多长。或者可以这么理解:就是表示TCP报文段中数据部分在整个TCP报文段中的位置。该字段的单位是32位字,即:4个字节。
URG:表示本报文段中发送的数据是否包含紧急数据。URG=1,表示有紧急数据。后面的紧急指针字段只有当URG=1时才有效。
ACK:表示是否前面的确认号字段是否有效。ACK=1,表示有效。只有当ACK=1时,前面的确认号字段才有效。TCP规定,连接建立后,ACK必须为1。
PSH:告诉对方收到该报文段后是否应该立即把数据推送给上层。如果为1,则表示对方应当立即把数据提交给上层,而不是缓存起来。
RST:只有当RST=1时才有用。如果你收到一个RST=1的报文,说明你与主机的连接出现了严重错误(如主机崩溃),必须释放连接,然后再重新建立连接。或者说明你上次发送给主机的数据有问题,主机拒绝响应。
SYN:在建立连接时使用,用来同步序号。当SYN=1,ACK=0时,表示这是一个请求建立连接的报文段;当SYN=1,ACK=1时,表示对方同意建立连接。SYN=1,说明这是一个请求建立连接或同意建立连接的报文。只有在前两次握手中SYN才置为1。
FIN:标记数据是否发送完毕。如果FIN=1,就相当于告诉对方:“我的数据已经发送完毕,你可以释放连接了”
窗口大小:表示现在运行对方发送的数据量。也就是告诉对方,从本报文段的确认号开始允许对方发送的数据量。
校验和:提供额外的可靠性。具体如何校验,参考其他资料。
紧急指针:标记紧急数据在数据字段中的位置。
选项部分:其最大长度可根据TCP首部长度进行推算。TCP首部长度用4位表示,那么选项部分最长为:(2^4-1)*4-20=40字节。
选项部分的应用:
MSS最大报文段长度(Maxium Segment Size):指明数据字段的最大长度,数据字段的长度加上TCP首部的长度才等于整个TCP报文段的长度。MSS值指示自己期望对方发送TCP报文段时那个数据字段的长度。通信双方可以有不同的MSS值。如果未填写,默认采用536字节。MSS只出现在SYN报文中。即:MSS出现在SYN=1的报文段中。
窗口扩大选项(Windows Scaling):由于TCP首部的窗口大小字段长度是16位,所以其表示的最大数是65535。但是随着时延和带宽比较大的通信产生(如卫星通信),需要更大的窗口来满足性能和吞吐率,所以产生了这个窗口扩大选项。
SACK选择确认项(Selective Acknowledgements):用来确保只重传缺少的报文段,而不是重传所有报文段。比如主机A发送报文段1、2、3,而主机B仅收到报文段1、3。那么此时就需要使用SACK选项来告诉发送方只发送丢失的数据。那么又如何指明丢失了哪些报文段呢?使用SACK需要两个功能字节。一个表示要使用SACK选项,另一个指明这个选项占用多少字节。描述丢失的报文段2,是通过描述它的左右边界报文段1、3来完成的。而这个1、3实际上是表示序列号,所以描述一个丢失的报文段需要64位即8个字节的空间。那么可以推算整个选项字段最多描述(40-2)/8=4个丢失的报文段。
时间戳选项(Timestamps):可以用来计算RTT(往返时间),发送方发送TCP报文时,把当前的时间值放入时间戳字段,接收方收到后发送确认报文时,把这个时间戳字段的值复制到确认报文中,当发送方收到确认报文后即可计算出RTT。也可以用来防止回绕序号PAWS,也可以说可以用来区分相同序列号的不同报文。因为序列号用32为表示,每2^32个序列号就会产生回绕,那么使用时间戳字段就很容易区分相同序列号的不同报文。
NOP(NO-Operation):它要求选项部分中的每种选项长度必须是4字节的倍数,不足的则用NOP填充。同时也可以用来分割不同的选项字段。如窗口扩大选项和SACK之间用NOP隔开。
用户数据报协议(UDP)
UDP全称是User Datagram Protocol,中文名为用户数据报协议。UDP 提供无连接的网络服务,该服务对消息中传输的数据提供不可靠的、最大努力传送。这意味着它不保证数据报的到达,也不保证所传送数据包的顺序是否正确。
虽然TCP中植入了各种安全保障功能,但是在实际执行的过程中会占用大量的系统开销,无疑使速度受到严重的影响。反观UDP由于排除了信息可靠传递机制,将安全和排序等功能移交给上层应用来完成,极大地降低了执行时间,使速度得到了保证。
Socket编程-Client
iOS中实现Socekt编程有下面几种方式:
- BSDSocket iOS系统基于unix,所以支持底层的BSD Socket。
|
|
- CFSocket 对底层BSD Socket进行轻量级的封装
|
|
- CocoaAsyncSocket 使用OC封装的一个socket框架(支持TCP和UDP)
github
这里使用的是CFSocket结合BSDSocket
创建socket对象并连接服务器
|
|
接收数据
|
|
判断当前连接成功后,可以开一个线程监听是否接收到数据。
注意这里的监听需要在子线程中进行。
|
|
发送数据
|
|
断开连接
|
|
Socket编程-Server
在本机搭建一个MAC APP模拟Server,实现和Client的通信。
创建Socket对象绑定端口
|
|
和Client相比多了一个setsockopt的过程。
Accept回调处理
|
|
创建一个可读写的Socket连接,当接收或者发送数据时,都会走到回调接口中。
读数据回调
|
|
写数据回调
|
|
保存当前写数据的实例。
发送数据
|
|
通信过程如下图: