什么是socket?
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。
我们知道两个进程如果需要进行通讯最基本的一个前提能能够唯一的标示一个进程,在本地进程通讯中我们可以使用PID来唯一标示一个进程,但PID只在本地唯一,网络中的两个进程PID冲突几率很大,这时候我们需要另辟它径了,我们知道IP层的ip地址可以唯一标示主机,而TCP层协议和端口号可以唯一标示主机的一个进程,这样我们可以利用ip地址+协议+端口号唯一标示网络中的一个进程,能够唯一标示网络中的进程后,它们就可以利用socket进行通信。
建立网络通信连接至少要一对端口号(socket)。socket本质是编程接口(API),对TCP/IP的封装,TCP/IP也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口;HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。
socket与http的区别
在网络七层架构中,http属于应用层协议,如图:图
而socket是位于应用层和传输层之间的一个抽象层,是本来不存在与七层架构中的:图
socket通信流程是怎样进行的?
socket的通信流程:
流程解读:
1. server端创建socket
2. server端绑定socket和端口号
3. server端监听该端口号
4. server端启动accept()接收来自client端的连接请求,此时有连接进入时会往后续执行,没有链接则会阻塞在此
5. client端创建socket
6. client端根据server端的ip和port连接server端(tcp的三次握手)
7. 如果第6步连接成功,在server端将会收到一个连接,假如这个连接名叫conn
8. client端向server端发送数据
9. server端从conn中读取到client端发送过来的数据
10. 任何一端都可以主动断开连接
socket中传输数据出现的问题
粘包:当server端用一个buff接收数据,发现buff中除了一个完整的包之外还有其他的数据。
半包:server端未接收到一个完整的包,只接收到了一部分。
socket的封包与拆包
在实际开发中往往会封装自己的数据,一般分为Head和Body,Head中除了封装额外的信息之外,还会封装Body的长度在里面。这样就形成了如下数据:
Head{ //头信息 (总共占用6个字节)
One byte //第一个标志 (1个字节)
Two byte //第二个标志 (1个字节)
Length int32 //存放Body的数据长度 (4个字节)
}
Body{ //消息体 (总共占用?+4个字节)
Name []byte //名字 (占用?个字节)
Age int32 //年龄 (占用4个字节)
}
Data{
Head
Body
}
server端要对接收到的数据[]byte进行拆包以防止粘包和半包情况的发生。
注:Data这个数据结构在server端和client端都应保持一致
封包过程:
将一个封装好的Data数据转化成[]byte,然后发送。
拆包过程:
1. 循环从conn中读取数据,每次循环都判断接收到的数据是否>=6,若是,则表明接收完了Head,若否,继续执行下一次循环,知道满足条件
2. 接收完Head后,将前6个字节的数据解析到Data的Head中,对于从conn接收到的数据长度减去6(得到的是接收到的Body数据的长度),判断这个结果是否>=Head中Length,若否,循环继续接收数据;若是,则解析出Length长度的数据放入Data的Body,自此之后的数据又重新用一个Data来解析并存放
这样拆包就解决了粘包和半包的问题。
golang代码实现
简书贴代码真是蛋疼,截图算了