什么是unixsocket
socket大家应该很熟悉,以tcp/ip协议族为传输协议,用于跨主机通信,而unixsocket就是在socket的框架上发展出一种IPC机制(进程间通信),UDS(UNIX Domain Socket)提供面向流和面向数据包两种API接口,类似于TCP和UDP,其中SOCK_STREAM是很可靠的,消息既不会丢失也不会顺序错乱,比传统的socket效率更高,一般是tcp传输的两倍unix进程通信,并且不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。
unixsocket服务端和客户端连接及发送消息的过程如下:

unixsocket在k8s sidecar中的实践
unixsocket用途也很广泛,比如docker与宿主机的数据传输和信息交换:

其次,还有一个好处是,这两个进程完全可以用不同的语言写,然后都用unixsocket去通信。
好啦,说了这么多让我介绍一种k8s的pod业务场景,比如说我们主业务是一个数据分析或规则引擎,它是需要有一些配置可供用户在前端配置的,比如说规则的开关啊,数据分析文件大小啊等等,然后分析出来的结果也需要发送出去,向用户展示,或者是有一些指标需要定期进行健康检查,比如说cpu使用率啊,内存占用率啊等等,因为性能的要求,一般数据分析或规则匹配引擎都是C/C++写的,而C非常不擅长去与restful接口去通信,以及配置的json序列反序列化的字符串处理,因此,我可以用考虑在同一个pod中起一个sidecar,而这个sidecar服务可以用Go写,然后主服务和sidecar可以用unixsocket进行通信,前提只要这两者有一个共享挂载的目录,比如说是:"/root/unixsocket/sidecar.sock",整体思路如下所示:

//C服务端,无所谓了,两边都需要传一些信息
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define UNIX_DOMAIN "/root/unixsocket/sidecar.sock"
#define READ_FROM_CLIENT 0X01
#define WRITE_TO_CLIENT 0x02
int main(void)
{
socklen_t clt_addr_len;
int listen_fd;
int com_fd;
int ret;
//int i;
static char data_buf[1024];
int len;
struct sockaddr_un clt_addr;
struct sockaddr_un srv_addr;
listen_fd = socket(PF_UNIX, SOCK_STREAM, 0);
if(listen_fd < 0) {
perror("cannot create communication socket");
return 1;
}
//set server addr_param
srv_addr.sun_family = AF_UNIX;
strcpy(srv_addr.sun_path,UNIX_DOMAIN);
unlink(UNIX_DOMAIN);
//bind sockfd & addr
ret = bind(listen_fd, (struct sockaddr*)&srv_addr, sizeof(srv_addr));
if(ret == -1) {
perror("cannot bind server socket");
close(listen_fd);
unlink(UNIX_DOMAIN);
return 1;
}
//listen sockfd
ret = listen(listen_fd,1);
if(ret == -1) {
perror("cannot listen the client connect request");
close(listen_fd);
unlink(UNIX_DOMAIN);
return 1;
}
while(1) {
//have connect request use accept
len = sizeof(clt_addr);
com_fd = accept(listen_fd,(struct sockaddr*)&clt_addr,&len);
if(com_fd < 0) {
perror("cannot accept client connect request");
close(listen_fd);
unlink(UNIX_DOMAIN);
return 1;
}
//read and printf sent client info
printf("\nReceive from client:\n");
memset(data_buf, 0, 1024);
read(com_fd, data_buf, sizeof(data_buf));
printf("Request is %s\n", data_buf);
memset(data_buf, 0, 1024);
strcpy(data_buf, "send message to client!!");
write(com_fd, data_buf, sizeof(data_buf));
printf("send message to client\n:");
memset(data_buf, 0, 1024);
close(com_fd);
}
close(listen_fd);
unlink(UNIX_DOMAIN);
return 0;
}
//Go客户端
package main
import (
"bufio"
"fmt"
"net"
"time"
)
var quitSemaphore chan bool
func main() {
var unixAddr *net.UnixAddr
unixAddr, _ = net.ResolveUnixAddr("unix", "/root/unixsocket/sidecar.sock")
conn, _ := net.DialUnix("unix", nil, unixAddr)
defer conn.Close()
fmt.Println("connected!")
go onMessageRecived(conn)
b := []byte("time\n")
conn.Write(b)
<-quitSemaphore
}
func onMessageRecived(conn *net.UnixConn) {
reader := bufio.NewReader(conn)
for {
msg, err := reader.ReadString('\n')
fmt.Println(msg)
if err != nil {
quitSemaphore <- true
break
}
time.Sleep(time.Second)
b := []byte(msg)
conn.Write(b)
}
}



Reference
本地socket unix domain socket_bingqingsuimeng的博客-CSDN博客
本机网络 IO 之 Unix Domain Socket 性能分析 - 知乎 (zhihu.com)
blog.csdn.net/Nurke/article/details/77621782
go语言实现unix domain socket 客户端/服务端_ebayboy的技术博客_51CTO博客
(编辑:晋中站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|