IPv6 Socket程序问题

发布于 2024-11-05 20:50:48 字数 9093 浏览 2 评论 0原文

似乎流程没有进入包含 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

怎会甘心 2024-11-12 20:50:48

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.

独自唱情﹋歌 2024-11-12 20:50:48

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

  1. 不要自己声明 errno - 使用标头。它可能是一个宏而不是int
  2. (根据@Boofhead)不要绑定客户端套接字
  3. 使用getaddrinfo()< /code> 而不是客户端中的 gethostbyname() 来获取服务器的地址。 gethostbyname() 不支持 IPv6

这三个中的最后一个实际上是真正的问题。我已经在 MacOS X 和 CentOS 5 上测试了您的代码,并且 gethostbyname() 仅返回 IPv4 地址。

I can see a few issues of varying degrees:

  1. Don't declare errno yourself - use the headers. It may be a macro instead of an int
  2. (per @Boofhead) don't bind the client socket
  3. Use getaddrinfo() instead of gethostbyname() in the client to get the server's address. gethostbyname() doesn't portably support IPv6

The 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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文