IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> IPV6 UDP socket报错:网络不可达 -> 正文阅读

[网络协议]IPV6 UDP socket报错:网络不可达

作者:second-recommend-box recommend-box

Linux 上IPv6 udp套接字在板子上总是出现网络不可达,在主机上只有发送缓存<40字节才 能发送,41个字节的都会出现网络不可达。

问题描述:
最开始只发现了再主机上可以跑(测试数据<40字节),然后移到板子上(由于需求,在
板子上测试的时候就直接测试60字节数据,然后就发现不通,但是当时没注意到这个差别)而且打印系统返回的错误“网络不可达”,就以为是板子的IPv6配置或是板子对v6套接字的支持问题。

存在问题代码

/*
 * IPv6套接字编程
 */

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>

#include <unistd.h> // for close()

//IPv6压缩格式地址
static char src[] = "fe80::aa5e:45ff:fe32:4cc4";
static char dst[] = "fe80::b934:59c9:1a44:a672";

int main()
{
    int udp6_socket,ret,addr_len;
    struct sockaddr_in6 saddr;
    struct sockaddr_in6 daddr;
    //char buffer[] = "Hello world6HHHHHHHHHHHHHHHHHHHHHHH";
    //u_int32_t buffer[360];

    u_int32_t buffer[360];
    // int buffer[360];
    //u_int16_t buf[360];
    for(size_t i = 0; i < 48; i++)
    {
        buffer[i] = 'A'+i;
        //buf[i] = 'A'+i;
    }
    //memcpy(buf,buffer,sizeof(buffer));

    /*
    u_int8_t * p = (u_int8_t *)buf;
    for(size_t i = 0; i < sizeof(buffer); i++)
    {
        p[i] = buffer[i];
    }
    */
   /*
   for(size_t i = 0; i < 50; i++)
   {
       printf("%x ",buf[i]);
       if (i%16 ==0) {
           printf("\n");
       }
       
   }
   */
   
    

    // 设置IPv6地址,这个函数支持三种IPv6地址格式,包括首选地址,压缩格式和映射格式
    if ((inet_pton(AF_INET6,(char *)&src[0], &saddr.sin6_addr) != 1))
    {
        printf("invalid ipv6 addr \r\n");
        return  -1;
    }

    if ((inet_pton(AF_INET6,(char *)&dst[0], &daddr.sin6_addr) != 1)) 
    {
        printf("invalid ipv6 adddr \r\n");
        return -1;
    }

    bzero(&saddr,sizeof(saddr));
    bzero(&saddr,sizeof(saddr));
    saddr.sin6_family = AF_INET6;
    saddr.sin6_port = htons(30000);

    daddr.sin6_family = AF_INET6;
    daddr.sin6_port = htons(40000);

    //创建IPv6套接字,IPv6使用AF_INET6
    udp6_socket = socket(AF_INET6, SOCK_DGRAM,0);
    int result = setsockopt(udp6_socket,SOL_SOCKET,SO_BINDTODEVICE,"eth0",sizeof("eth0"));
    if (result == -1) 
    {
        printf("setsockopt fail,errno: %d ,%s \n",errno,strerror(errno));        
    }
    
    if (udp6_socket == -1) 
    {
        printf("create udp6_socket fail\r\n");
        return -1;
    }

    //绑定地址
    addr_len = sizeof(struct sockaddr_in6);
    ///* ?????????Dont know why there will be an unreached error if I try to bind
    int i = bind(udp6_socket,(struct sockaddr*)&saddr, addr_len);
    if (i != 0) {
        printf("udp6 bind addr fail,errno: %d ,%s \n",errno,strerror(errno));
        //printf("errInfo: %s \r\n", strerror(errno));
        close(udp6_socket);
        return -1;
    }
    //*/
    
    i = 0;
    //发送
    while(1)
    {
        i++;
        //ret = sendto(udp6_socket, &buf[0], sizeof(buf), 0, (struct sockaddr *)&daddr, addr_len);
        // ret = sendto(udp6_socket, &buffer[0], 48, 0, (struct sockaddr *)&daddr, addr_len);
        ret = sendto(udp6_socket, buffer, 24, 0, (struct sockaddr *)&daddr, addr_len);
        if (ret > 0) 
        {
            printf("%d :udp6 send %d bytes success \r\n",i,ret);
        }
        else
        {
            printf("send errno: %d ,error: %s \n ",errno,strerror(errno));
            //break;
            sleep(1);
            continue;
        }
        sleep(1);
        
    }

    //关闭套接字
    close(udp6_socket);
    return 0;
}

解决过程:
1、 查看是否开启IPv6支持—不是
去了解一下IPv6机制
板子和主机都是有链路本地地址的,所以都是开启IPv6的。
2、然后就想着是不是IPv6的路由没配好,结果发现当双方是直连的时候,是本地链路IPv6地址,根本不需要配置理由,而且也是支持v6的

3、后来发现主机上有时候也会出现网络不可达的问题,
再仔细一看,发现发送缓存只要>40字节就会网络不可达,<40是可以正常传输的。

4、一下就蒙了,这是为啥,为啥刚好卡在40字节,就尝试改了改发送缓存数组的的类型

//这是原来定义的以8位位基本单位的缓存数组
unsigned char buf[20];

//改成其他大于8位的类型就都可以发送长度>40的数组就可以成功发送
unsigned u_int16_t buf[60];

5、把之前写的IPv6 原始套接字的代码跑了一下,发现可以跑

综上,说明不是板子对v6机制支持,或者v6路由配置的问题。

然后就重写了一下套接字部分的代码,(区别感觉就是使用的结构体不同了),然后就不存在上述问题了。ok

以下是能正确发送所有合理长度的IPv6 udp 套接字的代码版本

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <linux/sockios.h>
#include <sys/ioctl.h>
#include <net/if.h>

int main()
{
    int sd,i;
    sd = socket(AF_INET6,SOCK_DGRAM,0);
    if (sd < 0) {
        perror("socket");
        return -1;
    }

    struct ifreq req;
    strcpy(req.ifr_name,"eth0");
    if (ioctl(sd,SIOCGIFINDEX, &req) < 0) {
        perror("siocgifindex");
        return -2;
    }

    struct sockaddr_in6 to;
    to.sin6_family = AF_INET6;
    to.sin6_port = htons(10086);
    to.sin6_scope_id = req.ifr_ifindex;

    if (inet_pton(AF_INET6,"fe80::b934:59c9:1a44:a672", &to.sin6_addr) <= 0) {
        perror("pton");
        return -3;
    }
    
    char data[200];
    for(i = 0; i < 10; i++)
    {
        sprintf(data,"ipv6 udp test %d\n",i);
        // if (sendto(sd,data,strlen(data),0,(struct sockaddr *)&to, sizeof(to)) < 0) 
        if (sendto(sd,data,sizeof(data),0,(struct sockaddr *)&to, sizeof(to)) < 0) 
        {
            perror("sendto");
        }
        
    }
    
    close(sd);
    return 0;
}

总结:
唉,还是对Linux上使用套接字不太熟悉,遇到问题只能去网上找是不是有一样的问题,或者换代码,还是得对自己的代码思路清晰一点,增加解决问题的能力

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-08-11 12:47:32  更:2021-08-11 12:49:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 19:52:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码