IPv6示例程序在connect()上失败

问题描述 投票:-1回答:2

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()拒绝为无效。

linux sockets ipv6
2个回答
3
投票

主要问题是您没有正确填充serv_addr


0
投票

重构代码:

© www.soinside.com 2019 - 2024. All rights reserved.