ipv6 tcp server

本文介绍IPv6网络编程中遇到的问题及解决办法,包括使用特定网络接口进行ping和SSH连接,以及在TCP客户端和服务端编程中如何正确指定网络接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 参考:https://stackoverflow.com/questions/12260003/connect-returns-invalid-argument-with-ipv6-address

  2. 使用ping测试ipv6网络是否连接:

    1. ping6 fe80::be30:5bff:fec8:xxxx。报如下错误:connect: Invalid argument。

    2. ping6 -I em1 fe80::be30:5bff:fec8:xxxx。使用-I参数指定网络接口名时,ping正常工作。

  3. ssh连接:

    1. ssh root@fe80::be30:5bff:fec8:xxxx。报如下错误:ssh: connect to host fe80::be30:5bff:fec8:xxxx port 22: Invalid argument

    2. ssh root@fe80::be30:5bff:fec8:xxxx%em1. ipv6地址后使用%连接网络接口名,连接正常。

  4. 概括如上现象,得出如下结论:fe...开头的ipv6地址,需要指定一个与之相关联的网络接口才能正常工作。

  5. tcp客户端demo中,connect函数,需要在参数struct sockaddr_in6结构的sin6_scope_id字段指定网络接口id。可通过命令:ip -d addr。获取网络接口名和网络接口id的对应关系。注意:sin6_scope_id不需要进行字节序转换。

  6. ipv6 tcp server示例程序如下:

#include <sys/types.h>          // socket
#include <sys/socket.h>         // socket
#include <netinet/in.h>         // struct sockaddr_incli_client_socket_init(void)
#include <arpa/inet.h>
#include <sys/epoll.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define IPV6_TCP_SERVER_PORT 4444

int main(int argc, char *argv[])
{
        int ret = 0;
        int servfd = -1, len = 0;
        uint32_t event_flag = 0;
        struct sockaddr_in6 servaddr, cliaddr;

        servfd = socket(AF_INET6, SOCK_STREAM, 0);
        if (-1 == servfd) {
                perror("socket");
                ret = -1;
                goto errexit;
        }

        int reuse = 1;
        ret = setsockopt(servfd, 
                        SOL_SOCKET, 
                        SO_REUSEADDR, 
                        &reuse, 
                        (socklen_t ) sizeof(int));

        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin6_family = AF_INET6;
        servaddr.sin6_port = htons(IPV6_TCP_SERVER_PORT);
        ret = bind(servfd, 
                        (const struct sockaddr *) &servaddr, 
                        (socklen_t ) sizeof(struct sockaddr_in6));
        if (-1 == ret) {
                perror("bind");
                ret = -1;
                goto errexit;
        }

#define LISTEN_MAX  5
        ret = listen(servfd, LISTEN_MAX);
        if (-1 == ret) {
                perror("listen");
                ret = -1;
                goto errexit;
        }

        int epfd = -1;
        struct epoll_event event;

        epfd = epoll_create(LISTEN_MAX);
        if (-1 == ret) {
                perror("epoll_create");
                ret = -1;
                goto errexit;
        }

        memset(&event, 0, sizeof(struct epoll_event));
        event.data.fd = servfd;
        event.events = EPOLLIN | event_flag;
        epoll_ctl(epfd, EPOLL_CTL_ADD, servfd, &event);

        int nfds = 0, connfd = -1;
        char read_buf[256];
        struct epoll_event events;
        socklen_t clilen = sizeof(struct sockaddr_in);

        while (1) {
                nfds = epoll_wait(epfd, &events, 1, -1);
                if (-1 == nfds) {
                        printf("error occurs\n");
                        continue;
                } else if (0 == nfds) {
                        printf("timeout\n");
                } else {
                        if (servfd == events.data.fd) {
                                connfd = accept(servfd, (struct sockaddr *) &cliaddr, &clilen);
                                if (-1 == connfd) {
                                        perror("accept");
                                        continue;
                                }

                                memset(&event, 0, sizeof(struct epoll_event));
                                event.data.fd = connfd;
                                event.events = EPOLLIN | event_flag;
                                epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &event);

                                printf("new connect\n");

                        } else {
                                memset(read_buf, 0, sizeof(read_buf));
                                len = read(events.data.fd, read_buf, sizeof(read_buf));
                                if (0 == len) {
                                        printf("peer close\n");
                                        break;
                                } else {
                                        printf("recv [%s]\n", read_buf);
                                }
                        }
                }
        }
errexit:
        return ret;
}
  1. ipv6 tcp client示例程序如下:

#include <sys/types.h>          // socket
#include <sys/socket.h>         // socket
#include <netinet/in.h>         // struct sockaddr_incli_client_socket_init(void)
#include <arpa/inet.h>

#include <unistd.h>
#include <fcntl.h>

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
        int ret = 0;
        int cli_fd = -1;
        char *pc_serv_ip = NULL, *pc_serv_port = NULL;
        struct sockaddr_in6 servaddr, cliaddr;

        cli_fd = socket(AF_INET6, SOCK_STREAM, 0);
        if (-1 == cli_fd) {
                perror("socket");
                ret = -1;
                goto errexit;
        }

        if (3 != argc) {
                printf("\nUsage: ./cli ip port\n");
                ret = -1;
                goto errexit;
        }
        pc_serv_ip = argv[1];
        pc_serv_port = argv[2];
        printf("dest ip=%s, port=%s\r\n", pc_serv_ip, pc_serv_port);

        memset(&servaddr, 0, sizeof(servaddr));
        servaddr.sin6_family = AF_INET6;
        servaddr.sin6_port = htons(atoi(pc_serv_port));
        ret = inet_pton(AF_INET6, pc_serv_ip, &servaddr.sin6_addr);
        if (1 != ret) {
                perror("inet_pton");
                ret = -1;
                goto errexit;
        }
        //servaddr.sin6_scope_id = htonl(2);
        servaddr.sin6_scope_id = 2;

        ret = connect(cli_fd, (const struct sockaddr *) &servaddr, (socklen_t) sizeof(servaddr));
        if (-1 == ret) {
                perror("connect");
                goto errexit;
        }

        printf("Succeed to connect to server\r\n");

        char write_buf[256] = {"x"};
        while (1) {
                memset(write_buf, 0, sizeof(write_buf));
                snprintf(write_buf, sizeof(write_buf), "Hello ipv6 server.");
                write(cli_fd, write_buf, strlen(write_buf));

                break;
        }
errexit:
        return ret;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值