IPv6 Socket程序问题
似乎流程没有进入包含 ipv6server.c 中接受的“for”循环,因此无法接受并与客户端连接。有什么错误吗?此代码对于 IPV4 工作正常,但在 IPV6 更改后出现此问题
ipv6server.c
#include <stdio.h>
#include <stdlib.h> /* needed for os x */
#include <string.h> /* for memset */
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/errno.h> /* defines ERESTART, EINTR */
#include <sys/wait.h> /* 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 < 1024 || 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 <stdio.h>
#include <stdlib.h> /* needed for os x*/
#include <string.h> /* for strlen */
#include <netdb.h> /* for gethostbyname() */
#include <sys/socket.h>
#include <netinet/in.h>
#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 < 1024 || 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 (e.g. 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) < 0) {
perror("getsockname failed");
return 0;
}
printf("local port number = %d\n", ntohs(myaddr.sin6_port));
/* fill in the server's address and data */
/* htons() converts a short integer to a network representation */
memset((char*)&servaddr, 0, sizeof(servaddr));
servaddr.sin6_family = AF_INET6;
servaddr.sin6_port = htons(port);
/* look up the address of the server given its name */
hp = gethostbyname(host);
if (!hp) {
fprintf(stderr, "could not obtain address of %s\n", host);
return 0;
}
/* put the host's address into the server address structure */
memcpy((void *)&servaddr.sin6_addr, hp->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 */
}
Seems that flow not going in " for" loop containing accept in ipv6server.c and hence not able to accept and connect with the client. Whats the mistake ? This code is working fine for IPV4 but after IPV6 changes getting this problem
ipv6server.c
#include <stdio.h>
#include <stdlib.h> /* needed for os x */
#include <string.h> /* for memset */
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/errno.h> /* defines ERESTART, EINTR */
#include <sys/wait.h> /* 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 < 1024 || 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 <stdio.h>
#include <stdlib.h> /* needed for os x*/
#include <string.h> /* for strlen */
#include <netdb.h> /* for gethostbyname() */
#include <sys/socket.h>
#include <netinet/in.h>
#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 < 1024 || 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 (e.g. 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) < 0) {
perror("getsockname failed");
return 0;
}
printf("local port number = %d\n", ntohs(myaddr.sin6_port));
/* fill in the server's address and data */
/* htons() converts a short integer to a network representation */
memset((char*)&servaddr, 0, sizeof(servaddr));
servaddr.sin6_family = AF_INET6;
servaddr.sin6_port = htons(port);
/* look up the address of the server given its name */
hp = gethostbyname(host);
if (!hp) {
fprintf(stderr, "could not obtain address of %s\n", host);
return 0;
}
/* put the host's address into the server address structure */
memcpy((void *)&servaddr.sin6_addr, hp->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 */
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
hp = gethostbyname(host);
如果您传递“localhost”,您如何知道它会返回 IPv6 地址?它可能返回 IPv4 地址,如果您尝试将其复制到 servaddr.sin6_addr 中,事情就会崩溃。
使用 getaddrinfo() 并显式查找 AF_INET6 地址(或者更好的是,使您的程序独立于实际地址类型,请参见 此处),或使用全局
in6addr_loopback
作为服务器地址,用于使用本地主机进行测试。hp = gethostbyname(host);
How do you know this returns an IPv6 address if you pass it "localhost" ? It probably returns the IPv4 address, and things go belly up if you try to copy that into
servaddr.sin6_addr
Use getaddrinfo() and explicitly look for an AF_INET6 address (or better yet, make your program independent of the actual address types, see here), or use the global
in6addr_loopback
as the server address, for testing with localhost.我可以看到一些不同程度的问题:
int
绑定
客户端套接字getaddrinfo()< /code> 而不是客户端中的
gethostbyname()
来获取服务器的地址。gethostbyname()
不支持 IPv6这三个中的最后一个实际上是真正的问题。我已经在 MacOS X 和 CentOS 5 上测试了您的代码,并且
gethostbyname()
仅返回 IPv4 地址。I can see a few issues of varying degrees:
errno
yourself - use the headers. It may be a macro instead of anint
bind
the client socketgetaddrinfo()
instead ofgethostbyname()
in the client to get the server's address.gethostbyname()
doesn't portably support IPv6The last of the 3 is actually the real problem. I've tested your code on MacOS X and CentOS 5 and
gethostbyname()
only returns an IPv4 address.