基本概念
socket分类
socket提供了**流(stream)和数据报(datagram)**两种通信机制,即流socket和数据报socket
流socket基于TCP协议,是一个有序、可靠、双向字节流的通道,传输数据不会丢失、不会重复、顺序也不会错乱
数据报socket基于UDP协议,不需要建立和维持连接,可能会丢失或错乱。UDP不是一个可靠的协议,对数据的长度有限制,但是它的效率比较高
某些应用层协议,出于历史原因,受当时技术和网络条件限制,选择了基于UDP实现,其选择的理由现在很可能已经不再成立了
实时的音视频聊天可能采用的是UDP,这种业务可以接受数据的丢失且不必重传
简单的socket通信流程
主机字节序和网络字节序
https://www.cnblogs.com/xingguang1130/p/11643446.html
大端、小端字节序
网络字节序和主机字节序
网络字节序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节序采用big endian排序方式
不同的机器主机字节序不相同,与CPU设计有关,数据的顺序是由cpu决定的,而与操作系统无关。我们把某个给定系统所用的字节序称为主机字节序(host byte order)。比如x86系列CPU都是little-endian的字节序
由于这个原因不同体系结构的机器之间无法通信,所以要转换成一种约定的数序,也就是网络字节顺序
htons(), ntohs(), ntohl(),htonl()函数
ntohs, ntohl, htons,htonl的比较和详解
网络字节序与主机字节序之间的转换函数:**htons(), ntohs(), ntohl(),htonl()**
,位于头文件<netinet/in.h>
htons和ntohs完成16位无符号数的相互转换,htonl和ntohl完成32位无符号数的相互转换
htonl()--"Host to Network Long int" 32Bytesntohl()--"Network to Host Long int" 32Byteshtons()--"Host to Network Short int" 16Bytesntohs()--"Network to Host Short int" 16Bytes
在使用little endian的系统中,这些函数会把字节序进行转换
在使用big endian类型的系统中,这些函数会定义成空宏
TCP三次握手与四次挥手
TCP三次握手四次挥手详解
TCP三次握手详解-深入浅出(有图实例演示)
💡 主要是面试时候可能会问,实际编程帮助不大
TCP报文分包和粘包
分包:发送方发送字符串”helloworld”,接收方却接收到了两个字符串”hello”和”world”
粘包:发送方发送两个字符串”hello”+”wold”,接收方却一次性接收到了"helloworld"
下面的例子中就既有分包也有粘包的情况
服务端:
客户端(127.0.0.1)已连接
接收:这是第1个超级女生,编号001
接收:这是第2个超级女生,编号002这是第3个超级女生,编号003这是第4个超级女生,编号004这是第5个超级女生,编号005这是第6个超级女生,编号006这是第7个超级女生,编号007这是第8个超级女生,编号008这是第9个超级女生,编号009这是第10个超级女生,编号010这是第11个超级女生,编号011这是第12个超级女生,编号012这是第13个超级女生,编号013这是第14个超级女生,编号014这是第15个超级女生,编号015这是第16个超级女生,编号016这是第17个超级女生,编号017这是第18个超级女生,编号018这是第19个超级女生,编号019这是第20个超级女生,编号020这是第21个超级女生,编号021这是第22个超级女生,编号022这是第23个超级女生,编号023这是第24个超级女生,编号024这是第25个超级女生,编号025这是第26个超级女生,编号026这是第27个超级女生,编号027这是第28个超级女生,编号028这是@dq�
接收:第29个超级女生,编号029这是第30个超级女生,编号030这是第31个超级女生,编号031这是第32个超级女生,编号032这是第33个超级女生,编号033这是第34个超级女生,编号034这是第35个超级女生,编号035这是第36个超级女生,编号036这是第37个超级女生,编号037这是第38个超级女生,编号038这是第39个超级女生,编号039这是第40个超级女生,编号040这是第41个超级女生,编号041这是第42个超级女生,编号042这是第43个超级女生,编号043这是第44个超级女生,编号044这是第45个超级女生,编号045这是第46个超级女生,编号046这是第47个超级女生,编号047这是第48个超级女生,编号048这是第49个超级女生,编号049这是第50个超级女生,编号050这是第51个超级女生,编号051这是第52个超级女生,编号052这是第53个超级女生,编号053这是第54个超级女生,编号054这是第55个超级女生,编号055这�@dq�
接收:��第56个超级女生,编号056这是第57个超级女生,编号057这是第58个超级女生,编号058这是第59个超级女生,编号059这是第60个超级女生,编号060这是第61个超级女生,编号061这是第62个超级女生,编号062这是第63个超级女生,编号063这是第64个超级女生,编号064这是第65个超级女生,编号065这是第66个超级女生,编号066这是第67个超级女生,编号067这是第68个超级女生,编号068这是第69个超级女生,编号069这是第70个超级女生,编号070这是第71个超级女生,编号071这是第72个超级女生,编号072这是第73个超级女生,编号073这是第74个超级女生,编号074这是第75个超级女生,编号075这是第76个超级女生,编号076这是第77个超级女生,编号077这是第78个超级女生,编号078这是第79个超级女生,编号079这是第80个超级女生,编号080这是第81个超级女生,编号081这是第82个超级女生,编号082��@dq�
客户端:
发送:这是第51495个超级女生,编号51495
发送:这是第51496个超级女生,编号51496
发送:这是第51497个超级女生,编号51497
发送:这是第51498个超级女生,编号51498
发送:这是第51499个超级女生,编号51499
但是TCP传输数据能保证几点:
- 顺序不变,例如发送方发送hello,接收方也一定顺序接收到hello,这个是TCP协议承诺的,因此这点成为我们解决分包和粘包问题的关键
- 分割的包中间不会插入其他数据
在实际开发中,为了解决分包和粘包的问题,就一定要自定义一份协议,最常用的方法是:
- 报文长度+报文内容,如9999helloworld
- 报文长度ASCII码/或二进制的整数