Docker daemon 绑定到 Unix socket, 而不是 TCP Port. 默认情况下只有 root
账号可以访问 Unix socket, 所以一般需要操作Docker时需要使用 sudo docker
的方式.
下面介绍如果使用docker命令而不需要root账号:
# 创建 docker group sudo groupadd docker # 如果是使用包管理器安装docker, 有可能已经创建了这个group # 把当前用户添加到该 group sudo usermod -aG docker $USER # 使用以下命令激活该组, 或者退出重新登陆 newgrp docker
然后执行docker命令就不需要借助sudo了, Visual Studio Code 也可以正常使用容器开发了.
Unix socket 和 TCP Port 区别
Unix socket 和 TCP port 是两种不同的通信方式,适用于不同的场景。
- Unix socket:是一种在同一台机器上进行进程间通信的机制,通过文件系统上的一个 socket 文件来实现通信。它不需要网络协议栈,通信速度更快,更适合在同一台机器上进行进程间通信。
- TCP Port:是一种通过网络协议栈进行进程间通信的机制,通过 IP 地址和端口号来实现通信。它可以在不同台机器之间进行通信,适合在不同台机器之间进行进程间通信。
Unix socket 实现通信的原理
首先,进程需要创建一个 socket 文件,这个文件通常位于 /tmp 目录下。创建 socket 文件时,进程可以指定文件权限,以便其他进程可以读写该文件。
接下来,进程需要绑定 socket 文件,这样其他进程才能连接到该 socket。绑定 socket 文件后,进程需要调用 listen 函数来监听该 socket。
当其他进程需要与该 socket 连接时,需要先调用 connect 函数来连接该 socket。连接成功后,就可以在该 socket 上进行读写操作。
在两个进程连接成功后,就可以在该 socket 上进行读写操作来进行通信。读写操作可以使用 read 和 write 函数来实现。
如何创建创建一个 socket 文件
在 Linux 系统中,可以使用 socket 函数来创建一个 socket 文件。
下面是一个示例代码:
#include <sys/socket.h>
int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
// handle error
}
其中, AF_UNIX 是地址族,表示使用 Unix socket; SOCK_STREAM 是套接字类型, 表示使用 TCP 协议.
如果成功,函数会返回一个 socket 文件描述符,该文件描述符可以用来进行后续的 socket 操作。
另外, 在使用时还需要注意权限的问题, 因为 socket文件是普通文件, 所以需要为其设置权限, 以便其他进程可以访问.
在 Go 语言中,使用 net 包来实现 socket 通讯
在 Go 语言中,可以使用 net 包来实现 socket 通讯。 下面是一个简单的示例代码,它展示了如何创建一个服务端 socket 和一个客户端 socket,并在两者之间进行通信: package main import ( "fmt" "net" ) func main() { // 创建服务端 listener, err := net.Listen("tcp", ":8080") if err != nil { fmt.Println("Error listening:", err.Error()) return } defer listener.Close() fmt.Println("Listening on :8080") for { conn, err := listener.Accept() if err != nil { fmt.Println("Error accepting: ", err.Error()) return } go handleRequest(conn) } } func handleRequest(conn net.Conn) { defer conn.Close() buf := make([]byte, 1024) // 读取客户端数据 _, err := conn.Read(buf) if err != nil { fmt.Println("Error reading:", err.Error()) } // 发送数据到客户端 conn.Write([]byte("Hello World!")) }
import ( "fmt" "net" ) func main() { // 创建客户端 conn, err := net.Dial("tcp", "localhost:8080") if err != nil { fmt.Println("Error dialing:", err.Error()) return } defer conn.Close() // 发送数据到服务端 conn.Write([]byte("Hello Server!")) buf := make([]byte, 1024) // 读取服务端数据 _, err = conn.Read(buf) if err != nil { fmt.Println("Error reading:", err.Error()) } fmt.Println("Server says:", string(buf)) }