IPv6套接字程序问题

似乎流不会进入ipv6server.c中包含accept的“for”循环,因此无法接受并连接客户端。 是什么错误? 此代码适用于IPV4,但在IPV6更改后出现此问题

ipv6server.c #include  #include  /* needed for os x */ #include  /* for memset */ #include  #include  #include  /* defines ERESTART, EINTR */ #include  /* defines WNOHANG, for wait() */ #include "port.h" /* defines default port */ #ifndef ERESTART #define ERESTART EINTR #endif extern int errno; void serve(int port); /* main server function */ void disconn(void); main(int argc, char **argv) { extern char *optarg; extern int optind; int c, err = 0; int port = SERVICE_PORT; static char usage[] = "usage: %s [-d] [-p port]\n"; while ((c = getopt(argc, argv, "dp:")) != -1) switch (c) { case 'p': port = atoi(optarg); if (port  65535) { fprintf(stderr, "invalid port number: %s\n", optarg); err = 1; } break; case '?': err = 1; break; } if (err || (optind < argc)) { fprintf(stderr, usage, argv[0]); exit(1); } serve(port); } /* serve: set up the service */ void serve(int port) { int svc; /* listening socket providing service */ int rqst; /* socket accepting the request */ socklen_t alen; /* length of address structure */ struct sockaddr_in6 my_addr; /* address of this service */ struct sockaddr_in6 client_addr; /* client's address */ int sockoptval = 1; char hostname[128]; /* host name, for debugging */ gethostname(hostname, 128); /* get a tcp/ip socket */ /* AF_INET is the Internet address (protocol) family */ /* with SOCK_STREAM we ask for a sequenced, reliable, two-way */ /* conenction based on byte streams. With IP, this means that */ /* TCP will be used */ if ((svc = socket(AF_INET6, SOCK_STREAM, 0)) < 0) { perror("cannot create socket"); exit(1); } /* we use setsockopt to set SO_REUSEADDR. This allows us */ /* to reuse the port immediately as soon as the service exits. */ /* Some operating systems will not allow immediate reuse */ /* on the chance that some packets may still be en route */ /* to the port. */ setsockopt(svc, SOL_SOCKET, SO_REUSEADDR, &sockoptval, sizeof(int)); /* set up our address */ /* htons converts a short integer into the network representation */ /* htonl converts a long integer into the network representation */ /* INADDR_ANY is the special IP address 0.0.0.0 which binds the */ /* transport endpoint to all IP addresses on the machine. */ memset((char*)&my_addr, 0, sizeof(my_addr)); /* 0 out the structure */ my_addr.sin6_family = AF_INET6; /* address family */ my_addr.sin6_port = htons(port); my_addr.sin6_addr = in6addr_any; client_addr.sin6_family = AF_INET6; /* address family */ client_addr.sin6_port = htons(port); client_addr.sin6_addr = in6addr_any; /* bind to the address to which the service will be offered */ if (bind(svc, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0) { perror("bind failed"); exit(1); } /* set up the socket for listening with a queue length of 5 */ if (listen(svc, 5) < 0) { perror("listen failed"); exit(1); } printf("server started on %s, listening on port %d\n", hostname, port); /* loop forever - wait for connection requests and perform the service */ alen = sizeof(client_addr); /* length of address */ for (;;) { while ((rqst = accept(svc, (struct sockaddr *)&client_addr, &alen)) < 0) { /* we may break out of accept if the system call */ /* was interrupted. In this case, loop back and */ /* try again */ if ((errno != ECHILD) && (errno != ERESTART) && (errno != EINTR)) { perror("accept failed"); exit(1); } } printf("received a connection from: %s port %d\n", inet_ntoa(client_addr.sin6_addr), ntohs(client_addr.sin6_port)); shutdown(rqst, 2); /* close the connection */ } } ipv6client.c /* echoc: a demo of TCP/IP sockets connect usage: client [-h serverhost] [-p port] */ #include  #include  /* needed for os x*/ #include  /* for strlen */ #include  /* for gethostbyname() */ #include  #include  #include "port.h" /* defines default port */ int conn(char *host, int port); void disconn(void); main(int argc, char **argv) { extern char *optarg; extern int optind; int c, err = 0; char *prompt = 0; int port = SERVICE_PORT; /* default: whatever is in port.h */ char *host = "localhost"; /* default: this host */ static char usage[] = "usage: %s [-d] [-h serverhost] [-p port]\n"; while ((c = getopt(argc, argv, "dh:p:")) != -1) switch (c) { case 'h': /* hostname */ host = optarg; break; case 'p': /* port number */ port = atoi(optarg); if (port  65535) { fprintf(stderr, "invalid port number: %s\n", optarg); err = 1; } break; case '?': err = 1; break; } if (err || (optind < argc)) { /* error or extra arguments? */ fprintf(stderr, usage, argv[0]); exit(1); } printf("connecting to %s, port %d\n", host, port); if (!conn(host, port)) /* connect */ exit(1); /* something went wrong */ disconn(); /* disconnect */ return 0; } int fd; /* fd is the file descriptor for the connected socket */ /* conn: connect to the service running on host:port */ /* return 0 on failure, non-zero on success */ int conn(char *host, int port) { struct hostent *hp; /* host information */ unsigned int alen; /* address length when we get the port number */ struct sockaddr_in6 myaddr; /* our address */ struct sockaddr_in6 servaddr; /* server address */ printf("conn(host=\"%s\", port=\"%d\")\n", host, port); /* get a tcp/ip socket */ /* We do this as we did it for the server */ /* request the Internet address protocol */ /* and a reliable 2-way byte stream */ if ((fd = socket(AF_INET6, SOCK_STREAM, 0)) < 0) { perror("cannot create socket"); return 0; } /* bind to an arbitrary return address */ /* because this is the client side, we don't care about the */ /* address since no application will connect here --- */ /* INADDR_ANY is the IP address and 0 is the socket */ /* htonl converts a long integer (eg address) to a network */ /* representation (agreed-upon byte ordering */ memset((char *)&myaddr, 0, sizeof(myaddr)); myaddr.sin6_family = AF_INET6; myaddr.sin6_addr = in6addr_any; myaddr.sin6_port = htons(0); if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { perror("bind failed"); return 0; } /* this part is for debugging only - get the port # that the operating */ /* system allocated for us. */ alen = sizeof(myaddr); if (getsockname(fd, (struct sockaddr *)&myaddr, &alen) h_addr_list[0], hp->h_length); /* connect to server */ if (connect(fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) { perror("connect failed"); return 0; } return 1; } /* disconnect from the service */ void disconn(void) { printf("disconn()\n"); shutdown(fd, 2); /* 2 means future sends & receives are disallowed */ } 

hp = gethostbyname(host);

如果你将它传递给“localhost”,你怎么知道这会返回一个IPv6地址? 它可能会返回IPv4地址,如果您尝试将其复制到servaddr.sin6_addr ,事情servaddr.sin6_addr

使用getaddrinfo()并显式查找AF_INET6地址(或者更好,使程序独立于实际地址类型,请参见此处 ),或使用全局in6addr_loopback作为服务器地址,以便使用localhost进行测试。

我可以看到一些不同程度的问题:

  1. 不要自己声明errno – 使用标题。 它可能是一个宏而不是一个int
  2. (根据@Boofhead)不bind客户端套接字
  3. 在客户端使用getaddrinfo()而不是gethostbyname()来获取服务器的地址。 gethostbyname()不支持IPv6

3的最后一个实际上是真正的问题。 我在MacOS X和CentOS 5上测试了你的代码, gethostbyname()只返回一个IPv4地址。