上篇文章中介绍了 7 种socket套接字类型,哪些可以实现TCP的连接呢? 本篇文章主要用到其中的 SOCK_STREAM
套接字类型。
其他哪种套接字类型还可以实现呢,大家可以想一想~
SOCK_STREAM
是最常用的套接字类型,通常用于 TCP 协议。它提供面向连接的、可靠的、双向的字节流通信。
我们熟悉的 HTTP、HTTPS、FTP、SSH、SMTP等协议及相关应用都是基于TCP协议,然后都可以通过 SOCK_STREAM
套接字类型实现。
主要的特性
- 面向连接:通信前需要建立连接。
- 可靠传输:保证数据按顺序到达,不会丢失或重复。
- 字节流:数据没有固定边界,被视为连续的字节流。
- 双向通信:双方都可以发送和接收数据。
以Go语言为例,最常用的socket系统调用如下
系统调用 | 实际作用 |
---|---|
syscall.Socket() | 创建套接字 |
syscall.Bind() | 绑定地址和端口 |
syscall.Listen() | 开始监听连接 |
syscall.Accept() | 接受连接 |
syscall.Connect() | 连接到服务器 |
syscall.Close() | 关闭套接字 |
syscall.Read() | 读 |
syscall.Write() | 写 |
我们先根据下图理解TCP三次握手的过程
示例:发送TCP三层握手报文请求
go
func main() {
dstIP := net.ParseIP("192.168.1.1").To4()
dstPort := 8080
// socket系统调用
fd, err := syscall.Socket(
syscall.AF_INET,
syscall.SOCK_STREAM,
syscall.IPPROTO_TCP,
)
if err != nil {
log.Fatalf("create socket err: %v", err)
}
defer syscall.Close(fd)
dstAddr := &syscall.SockaddrInet4{Port: dstPort}
copy(dstAddr.Addr[:], dstIP.To4())
if err := syscall.Connect(fd, dstAddr); err != nil {
log.Fatalf("connect err: %v", err)
}
}
示例代码中,使用syscall.Socket()
系统调用函数,syscall.AF_INET
设置IPv4协议族,设置syscall.SOCK_STREAM
套接字类型,然后指定了 syscall.IPPROTO_TCP
协议,对应的协议编号6。
最后,通过syscall.Connect()
系统调用向目标 192.168.1.1:8080
发送三次握手请求。
注意:
syscall.SOCK_STREAM
套接字类型,不支持单独发送TCPsyn
包,需要更底层套接字类型。大家可以思考下,结合上图TCP三次握手的理解,客户端要发送两个数据包 syn 和 ack 完成三次握手,那如何通过系统调用的方式实现呢? 可以关注我后续的文章哦~~
这里有一个疑问❓ 标准库中net.DialTCP()
函数,采用的什么方式进行TCP连接的呢?让我们一探究竟~
这里以Go语言1.22源代码为例。

可以看到在 doDialTCPProto()
嵌套函数中,已经将 syscall.SOCK_STREAM
套接字类型穿给了下一层 internetSocket()
函数。
那么 net.DialTCP()
函数的本质TCP连接请求,也是通过 syscall.Socket()
系统调用方式实现的。

socketFunc()
函数,实则是 syscall.Socket()
的封装。

技术文章持续更新,请大家多多关注呀~~
搜索微信公众号,关注我【 帽儿山的枪手 】