访问本机网络的方式
访问同一台电脑上的网络,一般用的地址是 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 严格来说不是网络,是unix
和 linux
系统提供的一个进程间通信的方式,有点类似管道。看名字也知道,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 服务器
1package main
2
3import (
4 "fmt"
5 "io"
6 "net"
7)
8
9func main() {
10 listen, err := GetUnixListen("/tmp/test_server.sock")
11 if err != nil {
12 panic(err)
13 }
14
15 defer listen.Close()
16 for {
17 conn, err := listen.Accept()
18 if err != nil {
19 panic(err)
20 }
21
22 buf := make([]byte, 1024)
23 //读数据
24 n, err := conn.Read(buf)
25 if err != nil && err != io.EOF {
26 panic(err)
27 }
28 fmt.Printf("%s\n", buf[:n])
29
30 //写数据
31 _, err = conn.Write([]byte("hello"))
32 panic(err)
33 }
34}
35
36func GetUnixListen(addr string) (net.Listener, error) {
37 listen, err := net.Listen("unix", addr)
38 if err != nil {
39 return nil, err
40 }
41 return listen, nil
42}
unix domain
客户端
1package main
2
3import (
4 "fmt"
5 "io"
6 "net"
7)
8
9func main() {
10 conn, err := GetUnixConn("/tmp/test_server.sock")
11 if err != nil {
12 panic(err)
13 }
14
15 buff := make([]byte, 1024)
16 n, err := conn.Read(buff)
17 if err != nil {
18 if err != io.EOF {
19 panic(err)
20 }
21 }
22 fmt.Printf("%s\n", buff[:n])
23
24 conn.Write([]byte("ok"))
25}
26
27func GetUnixConn(addr string) (net.Conn, error) {
28 conn, err := net.Dial("unix", addr)
29 if err != nil {
30 return nil, err
31 }
32 return conn, nil
33}
可以看到,在go中使用 unix domain的api 和tcp基本没有区别。有区别的地方是在监听和连接的地方。
tcp 通过 IP
+端口
的方式来确定地址的,而unix domain 同时一个文件符 来确定地址。
当unix domain开启监听后,会在目录中创建一个文件。在上面的例子中,就会在 /tmp
目录中创建一个test_server.sock
文件。
这是一个特殊的文件通过 file
命令可以看到
1file test_server.sock
2test_server.sock: socket
如果在同一个目录下有一个同名的文件,unix domain 的监听就会失败。就像一个端口默认只能被监听一次一样。
unix domain 和 tcp loopback 性能对比
我没有过严格的性能测试,只是写了一些简单的测试看了一下,在发送小的数据包时,unix domain 的性能会好于 tcp。当发送大的数据包时,两者的性能差距可以忽略不计了。
这个也是符合预期的,小的数据包时,tcp会经过网络协议栈,当数据量变大时,网络协议栈的影响可以忽略不计了。
总结
- tcp look back
可以在多个平台使用,通过本机的虚拟网卡完成数据传输,需要经过网络协议栈,性能开销相对大一些。
- unix domain
只能在unix类系统中使用,是操作系统提供的一种进程间通信方式。不需要经过网络协议栈,性能相对高一些。