0%

tcp loopbcak与unix domain区别

访问本机网络的方式

访问同一台电脑上的网络,一般用的地址是 localhost 或者 127.0.0.1这两种方式,比如本机有一个Nginx服务器,想要访问本机Nginx,在浏览器中输入localhost 或者 127.0.0.1就能访问到Nginx的首页。如果要连接到本机的mysql, 在连接的时候,把地址填127.0.0.1就好了

tcp 本地回环

为什么使用localhost或者1270.0.1就能访问本机的网络或者程序呢,是因为在每台电脑上都有一个特殊的网络,这个网络就是本地回环(local loopback)。localhost可以看做是 127.0.0.1 的域名。一般在hosts文件中都会有一条配置,使 localhost 映射到1270.0.0.1

在linux系统(debin 11)中, 使用 ip a命令可以查看本机的网络

可以看到,第一个网络就是本地回环(loopback),他的 ip 地址就是就是 127.0.0.1

本地回环也是网络,是一个特殊的虚拟网卡。使用本地回环网络时,数据也会经过网络栈的封包和解包。

可以看到,tcp属于运输层(传输层)协议,所以在本机发送数据时,也会经过

1
传输层->网络层->lookback->网络层->传输层

这样一个过程。

unix domain

上面说了什么是 tcp 本地回环,那什么是 unix domain 呢。unix domain 严格来说不是网络,是unixlinux系统提供的一个进程间通信的方式,有点类似管道。看名字也知道,unix domain 只支持unix类的系统中,windows系统是不支持的。unix 的使用方式和 tcp很像,但是底层的工作原理差别却很大。

unix domain 中的数据传输 就不需要网络栈了,可以看做是操作系统做了一次内存中的一个数据复制。

使用 unix domain

如何使用tcp 相信都很熟了,就不上demo了。只上 unix domain 的代码吧。因为 unix domain 不支持 windows系统,所以要在linux或者unix系统中测试,下面会使用go在debin中测试一下

unix domain 和tcp 一样 也是分 服务器客户端

unix domain 服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package main

import (
"fmt"
"io"
"net"
)

func main() {
listen, err := GetUnixListen("/tmp/test_server.sock")
if err != nil {
panic(err)
}

defer listen.Close()
for {
conn, err := listen.Accept()
if err != nil {
panic(err)
}

buf := make([]byte, 1024)
//读数据
n, err := conn.Read(buf)
if err != nil && err != io.EOF {
panic(err)
}
fmt.Printf("%s\n", buf[:n])

//写数据
_, err = conn.Write([]byte("hello"))
panic(err)
}
}

func GetUnixListen(addr string) (net.Listener, error) {
listen, err := net.Listen("unix", addr)
if err != nil {
return nil, err
}
return listen, nil
}

unix domain 客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
"fmt"
"io"
"net"
)

func main() {
conn, err := GetUnixConn("/tmp/test_server.sock")
if err != nil {
panic(err)
}

buff := make([]byte, 1024)
n, err := conn.Read(buff)
if err != nil {
if err != io.EOF {
panic(err)
}
}
fmt.Printf("%s\n", buff[:n])

conn.Write([]byte("ok"))
}

func GetUnixConn(addr string) (net.Conn, error) {
conn, err := net.Dial("unix", addr)
if err != nil {
return nil, err
}
return conn, nil
}

可以看到,在go中使用 unix domain的api 和tcp基本没有区别。有区别的地方是在监听和连接的地方。

tcp 通过 IP+端口的方式来确定地址的,而unix domain 同时一个文件符 来确定地址。

当unix domain开启监听后,会在目录中创建一个文件。在上面的例子中,就会在 /tmp 目录中创建一个test_server.sock 文件。
这是一个特殊的文件通过 file命令可以看到

1
2
file test_server.sock 
test_server.sock: socket

如果在同一个目录下有一个同名的文件,unix domain 的监听就会失败。就像一个端口默认只能被监听一次一样。

unix domain 和 tcp loopback 性能对比

我没有过严格的性能测试,只是写了一些简单的测试看了一下,在发送小的数据包时,unix domain 的性能会好于 tcp。当发送大的数据包时,两者的性能差距可以忽略不计了。

这个也是符合预期的,小的数据包时,tcp会经过网络协议栈,当数据量变大时,网络协议栈的影响可以忽略不计了。

总结

  1. tcp look back

可以在多个平台使用,通过本机的虚拟网卡完成数据传输,需要经过网络协议栈,性能开销相对大一些。

  1. unix domain

只能在unix类系统中使用,是操作系统提供的一种进程间通信方式。不需要经过网络协议栈,性能相对高一些。