我正在使用Unix域套接字进行一些测试,我可以毫无问题地通过它们进行通信,但是,当我在测试程序的服务器端调用accept()
时,返回的struct sockaddr_un
没有' t包含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;
}
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;
}
重申一下这个问题:
为什么sun_path
在服务器上accept()
调用后未填写{{1}}?
答案 0 :(得分:4)
我真的不确定这是否是一个答案。可能它更像是关于某些研究的思考,尽管在阅读时可能仍然值得。
至少在Linux 3.16.0,NetBSD 6.1.4和Darwin 13.1.0内核中,accept(2)
填充的值似乎与协议无关。实际上,这意味着accept(2)
,struct sockaddr *
的第二个参数仅填充到所有协议之间共享的内容。因此,在成功acccept(2)
之后,您拥有的东西远非完整的struct sockaddr_un
。
可能没有人认为在accept(2)
的第一次实施完成时它会变得非常重要,现在我们仍然坚持这一点。幸运的是,有一种解决方法,如果有人丢失了用于调用bind(2)
的套接字的路径名,现在又想再找到它。
使用struct sockaddr_storage
和getsockname(2)
可以访问成员sun_path。因此,为了确保获得所有有用的详细信息,请在成功拨打getsockname(2)
后致电accept(2)
(这将在server.c
中的第40行之后放置):
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);
}
或者只是使用它:
#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;
}
这已经过测试,即。它编译并产生预期的结果,用于运行内核3.16.0的GNU / Linux系统,运行6.1.4内核的NetBSD系统,以及运行13.1.0内核的OS / X Mavericks系统。 accept(2)
的所有这些行为都是一致的:sun_path
在填充的结构中无处可寻。 getsockname(2)
的行为在不同的操作环境之间也是一致的,使所有协议特定的细节都可用。
答案 1 :(得分:0)
您尚未将客户端套接字绑定到某个地址。
您不需要将客户端套接字绑定到connect()工作的地址;但是,如果您希望在服务器中访问您的客户端地址,那么您必须绑定()。
有意义吗?
在连接客户端之前,只需设置对bind()的调用即可。确保您为客户端使用的路径有效并正常检查错误。