gpt4 book ai didi

c - Unix 域套接字 : Using datagram communication between one server process and several client processes

转载 作者:太空狗 更新时间:2023-10-29 16:21:48 24 4
gpt4 key购买 nike

我想在 Linux 上的几个进程之间建立 IPC 连接。我以前从未使用过 UNIX 套接字,因此我不知道这是否是解决此问题的正确方法。

一个进程接收数据(未格式化的,二进制的)并应使用数据报协议(protocol)(即类似于带有 AF_INET 的 UDP)通过本地 AF_UNIX 套接字分发此数据。从此进程发送到本地 Unix 套接字的数据应由监听同一套接字的多个客户端接收。接收器的数量可能会有所不同。

为此,使用以下代码创建套接字并向其发送数据(服务器进程):

struct sockaddr_un ipcFile;
memset(&ipcFile, 0, sizeof(ipcFile));
ipcFile.sun_family = AF_UNIX;
strcpy(ipcFile.sun_path, filename.c_str());

int socket = socket(AF_UNIX, SOCK_DGRAM, 0);
bind(socket, (struct sockaddr *) &ipcFile, sizeof(ipcFile));
...
// buf contains the data, buflen contains the number of bytes
int bytes = write(socket, buf, buflen);
...
close(socket);
unlink(ipcFile.sun_path);

此写入返回 -1 并带有 errno 报告 ENOTCONN(“传输端点未连接”)。我猜这是因为当前没有接收进程正在监听此本地套接字,对吗?

然后,我尝试创建一个连接到这个套接字的客户端。

struct sockaddr_un ipcFile;
memset(&ipcFile, 0, sizeof(ipcFile));
ipcFile.sun_family = AF_UNIX;
strcpy(ipcFile.sun_path, filename.c_str());

int socket = socket(AF_UNIX, SOCK_DGRAM, 0);
bind(socket, (struct sockaddr *) &ipcFile, sizeof(ipcFile));
...
char buf[1024];
int bytes = read(socket, buf, sizeof(buf));
...
close(socket);

此处,绑定(bind)失败(“地址已在使用中”)。那么,我是否需要设置一些套接字选项,或者这通常是错误的方法吗?

提前感谢您提出任何意见/解决方案!

最佳答案

在数据报配置中使用 Unix Domain Socket 有一个技巧。与流套接字(tcp 或 unix 域套接字)不同,数据报套接字需要为服务器和客户端定义端点。当在流套接字中建立连接时,客户端的端点由操作系统隐式创建。无论这对应于临时 TCP/UDP 端口,还是 unix 域的临时 inode,客户端的端点都是为您创建的。这就是为什么您通常不需要为客户端中的流套接字发出对 bind() 的调用。

您看到“地址已在使用”的原因是您告诉客户端绑定(bind)到与服务器相同的地址。 bind() 是关于断言外部身份的。两个套接字通常不能具有相同的名称。

对于数据报套接字,特别是 unix 域数据报套接字,客户端必须 bind() 到其自己的 端点,然后 connect()服务器的端点。这是您的客户端代码,稍作修改,并添加了一些其他好东西:

char * server_filename = "/tmp/socket-server";
char * client_filename = "/tmp/socket-client";

struct sockaddr_un server_addr;
struct sockaddr_un client_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_UNIX;
strncpy(server_addr.sun_path, server_filename, 104); // XXX: should be limited to about 104 characters, system dependent

memset(&client_addr, 0, sizeof(client_addr));
client_addr.sun_family = AF_UNIX;
strncpy(client_addr.sun_path, client_filename, 104);

// get socket
int sockfd = socket(AF_UNIX, SOCK_DGRAM, 0);

// bind client to client_filename
bind(sockfd, (struct sockaddr *) &client_addr, sizeof(client_addr));

// connect client to server_filename
connect(sockfd, (struct sockaddr *) &server_addr, sizeof(server_addr));

...
char buf[1024];
int bytes = read(sockfd, buf, sizeof(buf));
...
close(sockfd);

此时您的套接字应该已完全设置。我认为理论上你可以使用 read()/write(),但通常我会使用 send()/recv( ) 用于数据报套接字。

通常您会希望在每次调用后检查错误,然后发出 perror()。当出现问题时,它将极大地帮助您。通常,使用这样的模式:

if ((sockfd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) {
perror("socket failed");
}

这几乎适用于所有 C 系统调用。

最好的引用资料是 Steven 的《Unix 网络编程》。在第 3 版的第 15.4 节中,第 415-419 页展示了一些示例并列出了许多注意事项。

顺便引用一下

I guess this is because no receiving process is currently listening to this local socket, correct?

我认为您对服务器中 write() 的 ENOTCONN 错误的看法是正确的。 UDP 套接字通常不会提示,因为它无法知道客户端进程是否正在监听。然而,unix 域数据报套接字是不同的。事实上,如果客户端的接收缓冲区已满,write() 将实际阻塞而不是丢弃数据包。这使得 unix 域数据报套接字的 IPC 优于 UDP,因为 UDP 在负载下肯定会丢弃数据包,即使在本地主机上也是如此。另一方面,这意味着您必须小心写得快和读得慢的人。

关于c - Unix 域套接字 : Using datagram communication between one server process and several client processes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3324619/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com