Go Socket
本文最后更新于:2024年3月18日 凌晨
Go Socket
- Socket 是 BSD UNIX 的进程通信机制,通常也称作”套接字”,用于描述 IP 地址和端口,是一个通信链的句柄, Socket 可以理解为 TCP/IP 网络的 API,它定义了许多函数或例程,程序员可以用它们来开发 TCP/IP 网络上的应用程序,电脑上运行的应用程序通常通过”套接字”向网络发出请求或者应答网络请求。
Socket
是应用层与 TCP/IP 协议族通信的中间软件抽象层,在设计模式中,Socket
其实就是一个门面模式,它把复杂的 TCP/IP 协议族隐藏在Socket
后面,对用户来说只需要调用 Socket 规定的相关函数,让Socket
去组织符合指定的协议数据然后进行通信。
TCP 通信
TCP 服务端
- 一个 TCP 服务端可以同时连接很多个客户端,例如世界各地的用户使用自己电脑上的浏览器访问淘宝网,因为 Go 语言中创建多个 goroutine 实现并发非常方便和高效,所以我们可以每建立一次链接就创建一个 goroutine 去处理。
- TCP 服务端程序的处理流程:
- 监听端口。
- 接收客户端请求建立链接。
- 创建 goroutine 处理链接。
- 使用 Go 语言的 net 包实现的 TCP 服务端代码如下:
1 |
|
TCP 客户端
- 一个 TCP 客户端进行 TCP 通信的流程如下:
- 建立与服务端的链接。
- 进行数据收发。
- 关闭链接。
- 使用 Go 语言的 net 包实现的 TCP 客户端代码如下:
1 |
|
TCP 黏包
黏包示例
- 服务端代码如下:
1 |
|
- 客户端代码如下:
1 |
|
- 将上面的代码保存后,分别编译,先启动服务端再启动客户端,可以看到服务端输出结果如下:
1 |
|
- 客户端分 10 次发送的数据,在服务端并没有成功的输出 10 次,而是多条数据"粘”到了一起。
为什么会出现粘包
- 主要原因就是 tcp 数据传递模式是流模式,在保持长连接的时候可以进行多次的收和发。
- "粘包”可发生在发送端也可发生在接收端:
- 由 Nagle 算法造成的发送端的粘包: Nagle 算法是一种改善网络传输效率的算法,简单来说就是当我们提交一段数据给 TCP 发送时, TCP 并不立刻发送此段数据,而是等待一小段时间看看在等待期间是否还有要发送的数据,若有则会一次把这两段数据发送出去。
- 接收端接收不及时造成的接收端粘包: TCP 会把接收到的数据存在自己的缓冲区中,然后通知应用层取数据,当应用层由于某些原因不能及时的把 TCP 的数据取出来,就会造成 TCP 缓冲区中存放了几段数据。
解决办法
- 出现”粘包”的关键在于接收方不确定将要传输的数据包的大小,因此我们可以对数据包进行封包和拆包的操作。
- 封包:封包就是给一段数据加上包头,这样一来数据包就分为包头和包体两部分内容了(过滤非法包时封包会加入”包尾”内容),包头部分的长度是固定的,并且它存储了包体的长度,根据包头长度固定以及包头中含有包体长度的变量就能正确的拆分出一个完整的数据包。
- 我们可以自己定义一个协议,比如数据包的前 4 个字节为包头,里面存储的是发送的数据的长度。
1 |
|
- 接下来在服务端和客户端分别使用上面定义的
proto
包的Decode
和Encode
函数处理数据。 - 服务端代码如下:
1 |
|
- 客户端代码如下:
1 |
|
UDP 通信
UDP 协议
UDP 服务端
- 使用 Go 语言的
net
包实现的 UDP 服务端代码如下:
1 |
|
UDP 客户端
- 使用 Go 语言的
net
包实现的 UDP 客户端代码如下:
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!