Kev*_*n S 5 sockets linux unix-socket
我正在使用Unix域套接字进行一些测试,我可以毫无问题地通过它们进行通信,但是,当我accept()在测试程序的服务器端调用时,返回的struct sockaddr_un不包含sun_path.
我很确定Inet套接字在accept()通话后正确填写了地址和端口,所以我在测试程序中做错了什么,或者我期待错误的结果?
我正在运行CentOS 6.2和gcc 4.4.6.
示例代码:
server.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NAME "socket"
int main(int argc, char **argv)
{
int sock, msgsock, rval;
struct sockaddr_un server, client;
char buf[1024];
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, NAME);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) {
perror("binding stream socket");
exit(1);
}
printf("Socket has name %s\n", server.sun_path);
listen(sock, 5);
for (;;) {
socklen_t len = sizeof(client);
msgsock = accept(sock, (struct sockaddr *)&client, &len);
if (msgsock == -1)
perror("accept");
else do {
printf("strlen(sun_path) = %zu\n", strlen(client.sun_path));
bzero(buf, sizeof(buf));
if ((rval = read(msgsock, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
} while (rval > 0);
close(msgsock);
}
close(sock);
unlink(NAME);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
client.c
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define DATA "Half a league, half a league . . ."
int main(int argc, char **argv)
{
int sock;
struct sockaddr_un server;
if (argc < 2) {
printf("usage:%s <pathname>", argv[0]);
exit(1);
}
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, argv[1]);
if (connect(sock, (struct sockaddr *) &server,
sizeof(struct sockaddr_un)) < 0) {
close(sock);
perror("connecting stream socket");
exit(1);
}
if (write(sock, DATA, sizeof(DATA)) < 0)
perror("writing on stream socket");
close(sock);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
只是重申一下这个问题:
为什么在服务器上调用sun_path后没有填写accept()?
小智 4
我真的不确定这是否是一个答案。也许它更像是对一些研究的思考,尽管也许仍然值得阅读。
填充的值accept(2)似乎与协议无关,至少在 Linux 3.16.0、NetBSD 6.1.4 和 Darwin 13.1.0 内核中是如此。实际上,这意味着 , 的第二个参数accept(2)仅struct sockaddr *填充到所有协议之间共享的内容。所以成功后你手里所拥有的还acccept(2)远远不是完整的struct sockaddr_un。
在第一次实现完成时,可能没有人认为这会非常重要accept(2),而现在我们却陷入了困境。幸运的是,有一种解决方法,以防万一有人丢失了用于调用 的套接字的路径名bind(2),并且现在想再次找到它。
并且成员 sun_path 是可访问的struct sockaddr_storage。getsockname(2)因此,为了确保您获得所有有趣的详细信息,请getsockname(2)在成功调用后调用accept(2)(这将放在您的 中的第 40 行之后server.c):
struct sockaddr_storage ss;
socklen_t sslen = sizeof(struct sockaddr_storage);
if (getsockname(msgsock, (struct sockaddr *)&ss, &sslen) == 0) {
struct sockaddr_un *un = (struct sockaddr_un *)&ss;
printf("socket name is: %s\n", un->sun_path);
}
Run Code Online (Sandbox Code Playgroud)
或者只是使用这个:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define NAME "socket"
int main(int argc, char **argv)
{
int sock, msgsock, rval;
struct sockaddr_un server, client;
char buf[1024];
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
exit(1);
}
server.sun_family = AF_UNIX;
strcpy(server.sun_path, NAME);
if (bind(sock, (struct sockaddr *) &server, sizeof(struct sockaddr_un))) {
perror("binding stream socket");
exit(1);
}
printf("Socket has name %s\n", server.sun_path);
listen(sock, 5);
for (;;) {
socklen_t len = sizeof(client);
msgsock = accept(sock, (struct sockaddr *)&client, &len);
if (msgsock == -1)
perror("accept");
else do {
printf("strlen(sun_path) = %zu\n", strlen(client.sun_path));
struct sockaddr_storage ss;
socklen_t sslen = sizeof(struct sockaddr_storage);
if (getsockname(msgsock, (struct sockaddr *)&ss, &sslen) == 0) {
struct sockaddr_un *un = (struct sockaddr_un *)&ss;
printf("socket name is: %s\n", un->sun_path);
}
bzero(buf, sizeof(buf));
if ((rval = read(msgsock, buf, 1024)) < 0)
perror("reading stream message");
else if (rval == 0)
printf("Ending connection\n");
else
printf("-->%s\n", buf);
} while (rval > 0);
close(msgsock);
}
close(sock);
unlink(NAME);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这已经经过测试,即。它编译并产生预期的结果,可以在运行内核 3.16.0 的 GNU/Linux 系统、运行 6.1.4 内核的 NetBSD 系统以及运行 13.1.0 内核的配备 OS/X Mavericks 的系统上运行。在所有这些行为中,accept(2)都是一致的:sun_path在结构填充中无处可找到。不同操作环境之间的行为getsockname(2)也是一致的,使得所有协议特定的细节都可用。