IPv6示例程序在connect()上失败
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#include <ctype.h>
void error(const char * es)
{
fprintf(stderr, "Error: %s\n", es);
exit(1);
}
struct sockaddr * getadr(char * name)
{
struct addrinfo * p;
int r;
struct sockaddr_in6 * sap;
unsigned long long addrl, addrh;
printf("getadr: begin\n");
r = getaddrinfo(name, NULL, NULL, & p);
if (r) error(gai_strerror(r));
sap = NULL;
while (p && !sap) {
/* traverse the available addresses */
if (p - > ai_family == AF_INET6 && p - > ai_socktype == SOCK_STREAM) {
/* get the IPv6 address */
sap = (struct sockaddr_in6 * ) p - > ai_addr;
}
p = p - > ai_next;
}
if (!sap) error("No address found");
addrh = (unsigned long long) ntohl(sap - > sin6_addr.__in6_u.__u6_addr32[0]) << 32 |
(unsigned long long) ntohl(sap - > sin6_addr.__in6_u.__u6_addr32[1]);
addrl = (unsigned long long) ntohl(sap - > sin6_addr.__in6_u.__u6_addr32[2]) << 32 |
(unsigned long long) ntohl(sap - > sin6_addr.__in6_u.__u6_addr32[3]);
printf("Address: %llx:%llx:%llx:%llx:%llx:%llx:%llx:%llx\n",
addrh >> 48 & 0xffff, addrh >> 32 & 0xffff, addrh >> 16 & 0xffff, addrh & 0xffff,
addrl >> 48 & 0xffff, addrl >> 32 & 0xffff, addrl >> 16 & 0xffff, addrl & 0xffff);
printf("getadr: end\n");
return ((struct sockaddr * ) sap);
}
int main(int argc, char * argv[]) {
int sockfd = 0, n = 0;
char buff[1024];
struct sockaddr_in6 serv_addr;
int r;
struct sockaddr * sap;
if (argc != 3) {
printf("Usage: socket <server> <page>\n");
exit(1);
}
if ((sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
error("Could not create socket");
memset( & serv_addr, '0', sizeof(serv_addr));
serv_addr.sin6_family = AF_INET6;
serv_addr.sin6_port = htons(80);
printf("before address resolve\n");
if (isdigit(argv[1][0])) {
r = inet_pton(AF_INET6, argv[1], & serv_addr.sin6_addr);
if (r <= 0) error("inet_pton error occured");
} else {
sap = getadr(argv[1]);
memcpy( & serv_addr, sap, sizeof(struct sockaddr));
}
printf("after address resolve\n");
r = connect(sockfd, (struct sockaddr * ) & serv_addr, sizeof(serv_addr));
if (r < 0) error("Connect Failed");
printf("after connect\n");
/* send request */
sprintf(buff, "GET %s HTTP/1.1\r\n", argv[2]);
write(sockfd, buff, strlen(buff));
sprintf(buff, "Host: %s\r\n\r\n", "www.example.com" /*argv[1]*/ );
write(sockfd, buff, strlen(buff));
do {
r = read(sockfd, buff, sizeof(buff));
if (r > 0) {
buff[r] = 0;
printf("%s", buff);
}
} while (r);
return 0;
}
我安排了服务器参数,如果是数字,则由inet_pton()
进行评估,否则,它将通过getaddrinfo()
。 inet_pton()
设置地址并起作用。 getaddrinfo()
显然没有死于连接(挂断)。该示例程序是一个简单的网页获取和打印(不是https)。我使用www.example.com服务器进行了测试。
在以下示例中,请注意,我使用相同的地址getaddrinfo()
在一个数字示例中为我提供了密码,然后可以正常工作。
我在这里做错了什么?
编译就是gcc socket.c -o socket
。
$ socket6 www.example.com /
before address resolve
getadr: begin
Address: 2606:2800:220:1:248:1893:25c8:1946
getadr: end
after address resolve
^C
(hangs up in connect, CTL-C out of it)
$ socket6 2606:2800:220:1:248:1893:25c8:1946 /
before address resolve
after address resolve
after connect
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: max-age=604800
Content-Type: text/html; charset=UTF-8
...
(prints the rest of the page)
[我确实找到了类似的帖子,他们建议将接口名称添加到服务器名称中,例如www.example.com%enp2s0,但被getaddrinfo()
拒绝为无效。
主要问题是您没有正确填充serv_addr
。
重构代码: