为什么可以';我不能在ai_socktype中使用SOCK_RAW吗?

为什么可以';我不能在ai_socktype中使用SOCK_RAW吗?,c,sockets,ipv6,raw-sockets,C,Sockets,Ipv6,Raw Sockets,我正在尝试实现一个IPv6 UDP客户机服务器应用程序,它将让我获得逐跳扩展头的详细信息。因此,我想我必须使用SOCK_RAW来访问IPv6头信息 现在在我的客户机代码中,我有以下内容 #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #inc

我正在尝试实现一个IPv6 UDP客户机服务器应用程序,它将让我获得逐跳扩展头的详细信息。因此,我想我必须使用SOCK_RAW来访问IPv6头信息

现在在我的客户机代码中,我有以下内容

   #include <sys/types.h>
   #include <sys/socket.h>
   #include <netdb.h>
   #include <stdio.h>
   #include <stdlib.h>
   #include <unistd.h>
   #include <string.h>

   #define BUF_SIZE 500

   int
   main(int argc, char *argv[])
   {
       struct addrinfo hints;
       struct addrinfo *result, *rp;
       int sfd, s, j;
       size_t len;
       ssize_t nread;
       char buf[BUF_SIZE];

       if (argc < 3) {
           fprintf(stderr, "Usage: %s host port msg...\n", argv[0]);
           exit(EXIT_FAILURE);
       }

       /* Obtain address(es) matching host/port */

       memset(&hints, 0, sizeof(struct addrinfo));
       hints.ai_family = AF_INET6;    /* Allow IPv4 or IPv6 */
       hints.ai_socktype = SOCK_RAW; /* Datagram socket */
       hints.ai_flags = 0;
       hints.ai_protocol = 0;          /* Any protocol */

       s = getaddrinfo(argv[1], argv[2], &hints, &result);
       if (s != 0) {
           fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
           exit(EXIT_FAILURE);
       }

       /* getaddrinfo() returns a list of address structures.
          Try each address until we successfully connect(2).
          If socket(2) (or connect(2)) fails, we (close the socket
          and) try the next address. */

       for (rp = result; rp != NULL; rp = rp->ai_next) {
           sfd = socket(rp->ai_family, rp->ai_socktype,
                        rp->ai_protocol);
           if (sfd == -1)
               continue;

           if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
               break;                  /* Success */

           close(sfd);
       }

       if (rp == NULL) {               /* No address succeeded */
           fprintf(stderr, "Could not connect\n");
           exit(EXIT_FAILURE);
       }

       freeaddrinfo(result);           /* No longer needed */

       /* Send remaining command-line arguments as separate
          datagrams, and read responses from server */

       for (j = 3; j < argc; j++) {
           len = strlen(argv[j]) + 1;
                   /* +1 for terminating null byte */

           if (len + 1 > BUF_SIZE) {
               fprintf(stderr,
                       "Ignoring long message in argument %d\n", j);
               continue;
           }

           if (write(sfd, argv[j], len) != len) {
               fprintf(stderr, "partial/failed write\n");
               exit(EXIT_FAILURE);
           }

           nread = read(sfd, buf, BUF_SIZE);
           if (nread == -1) {
               perror("read");
               exit(EXIT_FAILURE);
           }

           printf("Received %ld bytes: %s\n", (long) nread, buf);
       }

       exit(EXIT_SUCCESS);
   }
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义BUF_尺寸500
int
main(int argc,char*argv[])
{
结构addrinfo提示;
结构addrinfo*结果,*rp;
国际科学基金会,s,j;
尺寸透镜;
ssize_t nread;
字符大小[buf_SIZE];
如果(argc<3){
fprintf(stderr,“用法:%s主机端口消息…\n”,argv[0]);
退出(退出失败);
}
/*获取与主机/端口匹配的地址*/
memset(&hints,0,sizeof(struct addrinfo));
hits.ai_family=AF_INET6;/*允许IPv4或IPv6*/
hits.ai_socktype=SOCK_RAW;/*数据报套接字*/
hints.ai_flags=0;
hints.ai_protocol=0;/*任何协议*/
s=getaddrinfo(argv[1]、argv[2]、提示和结果);
如果(s!=0){
fprintf(标准,“getaddrinfo:%s\n”,gai_strerror(s));
退出(退出失败);
}
/*getaddrinfo()返回地址结构的列表。
尝试每个地址,直到我们成功连接(2)。
如果插座(2)(或连接(2))出现故障,我们(关闭插座
和)尝试下一个地址*/
for(rp=result;rp!=NULL;rp=rp->ai\u next){
sfd=插座(rp->ai_系列,rp->ai_插座类型,
rp->ai_协议);
如果(sfd==-1)
继续;
如果(连接(sfd,rp->ai地址,rp->ai地址)!=-1)
中断;/*成功*/
关闭(sfd);
}
如果(rp==NULL){/*没有地址成功*/
fprintf(stderr,“无法连接”\n);
退出(退出失败);
}
freeaddrinfo(结果);/*不再需要*/
/*将剩余的命令行参数作为单独的参数发送
数据报,并从服务器读取响应*/
对于(j=3;j基本尺寸){
fprintf(标准,
“忽略参数%d中的长消息\n”,j);
继续;
}
if(写入(sfd,argv[j],len)!=len){
fprintf(stderr,“部分/失败写入\n”);
退出(退出失败);
}
nread=读取(sfd、buf、buf_大小);
如果(nread==-1){
佩罗(“阅读”);
退出(退出失败);
}
printf(“已接收%ld个字节:%s\n”,(长)nread,buf);
}
退出(退出成功);
}
我知道我在使用SOCK_RAW时没有为数据包编好标题。我只是想做一次试运行,看看我得到了什么错误。它在getaddrinfo()中失败,出现以下错误

getaddrinfo():ai_socktype不支持servname

我关心的是,它不应该在这里失败,而应该在它向套接字发送一些数据时失败,或者在创建套接字时失败

这是什么原因

对于SOCK_RAW,在IPv6中构造数据包时,我是否也需要处理校验和,或者这是由内核完成的。从目前为止我所读到的内容来看,必须为ICMPv6处理校验和计算


请让我知道我是否做对了事情,以及我是否朝着正确的方向前进

我想这是失败的,因为你用两个参数来调用它

从getaddrinfo的手册页:

请求的服务对于请求的套接字类型不可用。[...] 如果服务不为NULL,并且hints.ai_socktype为SOCK_RAW(不支持服务概念的套接字类型),则可能发生错误


只需给NULL而不是
argv[2]

您的代码在OS/X Mavericks上对我有效,但前提是本地主机和目标主机配置了IPv6地址。为什么我没有读到这一点呢?:我一直在像crazyy一样阅读手册页,以找出我的错误。谢谢你!这确实节省了一些时间:p