我在我的Mac上编写了一个网络应用程序,它应该在Linux上运行,因为我认为“嘿,POSIX是POSIX,它应该可以工作”,现在我收到连接到服务器的错误。
TCP_sock = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (TCP_sock < 0) {
syserr("socket");
}
TCP_open = 1;
memset(&addr_hints, 0, sizeof(struct addrinfo));
addr_hints.ai_flags = 0;
addr_hints.ai_family = AF_UNSPEC;
addr_hints.ai_socktype = SOCK_STREAM;
addr_hints.ai_protocol = IPPROTO_TCP;
addr_hints.ai_addrlen = 0;
addr_hints.ai_addr = NULL;
addr_hints.ai_canonname = NULL;
addr_hints.ai_next = NULL;
rc = getaddrinfo(SERVER, PORT, &addr_hints, &addr_result);
if (rc != 0) {
cleanup();
fprintf(stderr, "rc=%d\n", rc);
syserr("getaddrinfo: %s\n", gai_strerror(rc));
continue;
}
if ((rc = connect(TCP_sock, addr_result->ai_addr, addr_result->ai_addrlen)) != 0) {
syserr("connect: %s\n", gai_strerror(rc));
cleanup();
continue;
}
我收到了一个错误:
ERROR: connect: Bad value for ai_flags
(22; Invalid argument)
只是为了说清楚:
SERVER = "localhost"
PORT = "1234"
当然,在该PORT上有一个运行在localhost上的服务器。什么可能是错的?
答案 0 :(得分:0)
根据this Wikipedia article on getaddrinfo,实施因系统而异。另外,OS X is not fully POSIX compliable(第一段)。它被认证为符合SUSv3,但这并不意味着它完全符合POSIX标准,并且它不一定实现与其他POSIX-y系统相同的通用功能。
因此,虽然'POSIX是POSIX',但OS X不是POSIX。您需要了解所调用方法的实现细节,并弄清楚它们之间的区别。
答案 1 :(得分:0)
这里有几个问题。
与其他评论一样,您正在创建一个IPv6套接字,然后告诉getaddrinfo您可以使用IPv4或IPV6地址。将AF_UNSPEC更改为AF_INET6,它应该有所帮助。所以应该更好地工作的代码(考虑到#1和#2)
TCP_sock = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (TCP_sock < 0) {
syserr("socket");
}
TCP_open = 1;
memset(&addr_hints, 0, sizeof(struct addrinfo));
addr_hints.ai_flags = 0;
addr_hints.ai_family = AF_INET6;
addr_hints.ai_socktype = SOCK_STREAM;
addr_hints.ai_protocol = IPPROTO_TCP;
addr_hints.ai_addrlen = 0;
addr_hints.ai_addr = NULL;
addr_hints.ai_canonname = NULL;
addr_hints.ai_next = NULL;
rc = getaddrinfo(SERVER, PORT, &addr_hints, &addr_result);
if (rc != 0) {
cleanup();
fprintf(stderr, "rc=%d\n", rc);
syserr("getaddrinfo: %s\n", gai_strerror(rc));
continue;
}
if ((rc = connect(TCP_sock, addr_result->ai_addr, addr_result->ai_addrlen)) != 0) {
syserr("connect: %s\n", strerror(errno));
cleanup();
continue;
}
使用getaddrinfo的常用方法是先调用它,然后使用addrinfo结构中的信息创建套接字并连接它。 Linux手册页有一个很好的例子,这里有相关的摘录。
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */
hints.ai_protocol = 0; /* Any protocol */
hints.ai_canonname = NULL;
hints.ai_addr = NULL;
hints.ai_next = NULL;
s = getaddrinfo(NULL, argv[1], &hints, &result);
if (s != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
exit(EXIT_FAILURE);
}
/* getaddrinfo() returns a list of address structures.
Try each address until we successfully bind(2).
If socket(2) (or bind(2)) fails, we (close the socket
and) try the next address. */
for (rp = result; rp != NULL; rp = rp->ai_next) {
sfd = socket(rp->ai_family, rp->ai_socktype,
rp->ai_protocol);
if (sfd == -1)
continue;
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
break; /* Success */
close(sfd);
}
if (rp == NULL) { /* No address succeeded */
fprintf(stderr, "Could not bind\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(result); /* No longer needed */
这里主要的是你使用addrinfo结构中的ai_family,ai_socktype和ai_protocol来创建适合在结构中与sockaddr一起使用的套接字。