1.概念
uds(Unix domain socket):
当我们的两个进程在不同的机器上时,可以使用tcp/udp通信.
但是当两个进程在一个主机上,我们可以使用UDS.
IPC 机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。
3个特点:
- Unix域套接口往往比位于同一主机的TCP套接口快出一倍。因为不需要走协议栈,不需要打包拆包、计算校验和、维护序号和应答等,基于文件系统.
- Unix域套接口可用于在同一主机上的不同进程之间传递描述字。所以可以无损升级.
- Unix域套接口把客户的凭证(用户ID和用户组ID)提供给服务器,从而实现能够提供额外的安全检查措施
第二点,fd不就是个数字吗,为什么这么费劲迁移?
注意:每个进程打开一个文件,都会生成一个fd.如下图,两个进程,打开同一个文件.就会产生两个fd.两个fd对应的文件表项.虽然里面有一个指针都指向同一个文件.但每个文件表项里文件的偏移量等动态信息都不一样.因此啥叫fd迁移,就是让两个进程的文件表项都指向一个.或者说a进程打开了a.txt文件,产生了fd=1; 此时b进程要用a进程的fd=1的文件表项,并且继续对fd=1进行操作.
fd迁移的效果:
2.demo编写
2.1 服务端
package main
import (
"fmt"
"net"
"syscall"
)
var (
Sock_addr = "/data/logs/uds/test_sock"
)
func main() {
syscall.Unlink(Sock_addr)
//=====1.mosn启动后,来监听reconfig这个uds
l, err := net.Listen("unix", Sock_addr)
//注意这里,目录需要提前建好,但是不要建立文件,否则会报错,address has bind.哦 ,所以mosn里面每次要unlink一下
if err != nil {
fmt.Println(err.Error())
return
}
defer l.Close()
ul := l.(*net.UnixListener)
for {
//=======2.当accept到连接后.
uc, err := ul.AcceptUnix()
if err != nil {
return
}
//3.写入一个字符串数据作为回应
_, err = uc.Write([]byte("ljl"))
if err != nil {
continue
}
//4.可以关闭连接了
uc.Close()
}
}
macbook-air:uds jl.li_local$ ll /data/logs/uds/
total 0
drwxr-xr-x 3 jl.li_local wheel 96 12 6 12:01 ./
drwxrwxrwx 62 jl.li wheel 1984 12 6 11:59 ../
srwxr-xr-x 1 jl.li wheel 0 12 6 12:01 test_sock=
可以看到,运行起来后,在文件目录下,建立了一个s类型的文件.
另外,如果再次启动的话,会报错,
listen unix /data/logs/uds/test_sock: bind: address already in use
因为已经有这个文件了,所以认为已经被绑定了.
所以需要删除这个文件,执行syscall.Unlink(Sock_addr)
2.2 客户端
package main
import (
"fmt"
"net"
"strconv"
"time"
)
func main() {
var unixConn net.Conn
var err error
unixConn, err = net.DialTimeout("unix", "/data/logs/uds/test_sock", 1*time.Second)
if err != nil {
fmt.Println("client error" + err.Error())
}
defer unixConn.Close()
uc := unixConn.(*net.UnixConn)
buf := make([]byte, 3)
n, _ := uc.Read(buf)
fmt.Println("收到返回,字节长度", strconv.Itoa(n)+",内容:"+string(buf))
}
运行起来后,会接受3个字节,
收到返回,字节长度 3,内容:ljl
3.应用
istio中 业务进程和envoy就是通过uds进行的通信.mosn在0.17.0貌似也支持了