SO_BINDTODEVICE Linux套接字选项问题

SO_BINDTODEVICE Linux套接字选项问题,第1张

概述我有一台带两个网卡的电脑.一个(eth0)用于LAN /互联网,另一个用于与一个微控制器设备的UDP通信.微控制器具有IP(192.168.7.2)和MAC地址.第二个pc网络适配器(eth1)具有192.168.7.1. 微控制器具有非常简单的IP堆栈,因此mc发送UDP数据包的最简单方法是广播它们. 在PC端,我想接收广播,但只能从eth1接收.所以我试图将UDP套接字绑定到eth1设备. 问 我有一台带两个网卡的电脑.一个(eth0)用于LAN /互联网,另一个用于与一个微控制器设备的UDP通信.微控制器具有IP(192.168.7.2)和MAC地址.第二个pc网络适配器(eth1)具有192.168.7.1.

微控制器具有非常简单的IP堆栈,因此mc发送UDP数据包的最简单方法是广播它们.

在PC端,我想接收广播,但只能从eth1接收.所以我试图将UDP套接字绑定到eth1设备.

问题(源代码如下):

> setsockopt(sock,Sol_SOCKET,SO_BINDTODEVICE,device,sizeof(device))需要root权限,为什么? (设置其他选项作为用户)
> getsockopt(sock,(voID *)buffer,& opt_length)给出“协议不可用”.我想通过setsockopt命令读回我设置的设备.
>哪里可以找到好的信息?我检查了一些Linux编程,网络书籍,但例如我只在互联网上找到的SO_BINDTODEVICE选项.

我的冗长(脏)测试程序显示问题.设置并返回SO_RCVTIMEO和SO_broADCAST选项的工作原理.

以用户身份运行代码:

Could not set SO_BINDTODEVICE (Operation not permitted)"

运行sudo给出:

SO_BINDTODEVICE set./mc-test: Could not get SO_BINDTODEVICE (Protocol not available)

所以,设置选项似乎工作,但读回是不可能的?

/* SO_BINDTODEVICE test */ #include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <stdio.h>#include <unistd.h>#include <string.h>#include <stdlib.h>#include <sys/time.h>#include <errno.h>#define MC_IP "192.168.7.2"#define MC_PORT (54321)#define MY_PORT (54321)#define MY_DEVICE "eth1"#define BUFFERSIZE (1000)/* global variables */int sock;struct sockaddr_in MC_addr;struct sockaddr_in my_addr;char buffer[BUFFERSIZE];int main(int argc,char *argv[]) {  unsigned int echolen,clIEntlen;  int rc,n;  char opt_buffer[1000];  struct protoent *udp_protoent;  struct timeval receive_timeout;  int optval;  socklen_t opt_length;  /* Create the UDP socket */  if ((sock = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP)) < 0)   {    printf ("%s: Failed to create UDP socket (%s) \n",argv[0],strerror(errno));    exit (EXIT_FAILURE);  }  printf ("UDP socket created\n");  /* set the recvfrom timeout value */  receive_timeout.tv_sec = 5;  receive_timeout.tv_usec = 0;  rc=setsockopt(sock,SO_RCVTIMEO,&receive_timeout,sizeof(receive_timeout));  if (rc != 0)   {     printf ("%s: Could not set SO_RCVTIMEO (%s)\n",strerror(errno));     exit (EXIT_FAILURE);  }  printf ("set timeout to\ntime [s]: %d\ntime [ms]: %d\n",receive_timeout.tv_sec,receive_timeout.tv_usec);  /* verify the recvfrom timeout value */  rc=getsockopt(sock,&opt_length);  if (rc != 0)   {     printf ("%s: Could not get socket options (%s)\n",strerror(errno));     exit (EXIT_FAILURE);  }  printf ("timeout value\ntime [s]: %d\ntime [ms]: %d\n",receive_timeout.tv_usec);  /* allow broadcast messages for the socket */  int true = 1;  rc=setsockopt(sock,SO_broADCAST,&true,sizeof(true));  if (rc != 0)   {     printf ("%s: Could not set SO_broADCAST (%s)\n",strerror(errno));     exit (EXIT_FAILURE);  }  printf ("set SO_broADCAST\n");  /* verify SO_broADCAST setting */  rc=getsockopt(sock,&optval,&opt_length);  if (optval != 0)   {    printf("SO_broADCAST is enabled\n");  }  /* bind the socket to one network device */  const char device[] = MY_DEVICE;  rc=setsockopt(sock,sizeof(device));  if (rc != 0)   {     printf ("%s: Could not set SO_BINDTODEVICE (%s)\n",strerror(errno));     exit (EXIT_FAILURE);  }  printf ("SO_BINDTODEVICE set\n");  /* verify SO_BINDTODEVICE setting */  rc = getsockopt(sock,&opt_length);  if (rc != 0)   {     printf ("%s: Could not get SO_BINDTODEVICE (%s)\n",strerror(errno));     exit (EXIT_FAILURE);  }  if (rc == 0)   {    printf("SO_BINDTODEVICE is: %s\n",buffer);  }  /* Construct the server sockaddr_in structure */  memset(&MC_addr,sizeof(MC_addr));     /* Clear struct */  MC_addr.sin_family = AF_INET;         /* Internet/IP */  MC_addr.sin_addr.s_addr = inet_addr(MC_IP);   /* IP address */  MC_addr.sin_port = htons(MC_PORT);        /* server port */  /* bind my own Port */  my_addr.sin_family = AF_INET;  my_addr.sin_addr.s_addr = INADDR_ANY; /* INADDR_ANY all local addresses */  my_addr.sin_port = htons(MY_PORT);  rc = bind (sock,(struct sockaddr *) &my_addr,sizeof(my_addr));  if (rc < 0)   {     printf ("%s: Could not bind port (%s)\n",strerror(errno));     exit (EXIT_FAILURE);  }  printf ("port bound\n");  /* IDentify mc */  buffer[0] = (char)1;  buffer[1] = (char)0;  send_data (buffer,2);    printf ("sent command: %d\n",(char)buffer[0]);  rc=receive_data(buffer);  printf ("%d bytes received\n",rc);  buffer[rc] = (char)0; /* string end symbol */  printf ("%d - %s\n",(int)(char)buffer[0],&buffer[1]);  close(sock);  printf ("socket closed\n");  exit(0);}/* send data to the MC *****************************************************//* buffer points to the bytes to send *//* buf_length is the number of bytes to send *//* returns allways 0 */int send_data( char *buffer,int buf_length ){  int rc;  rc = sendto (sock,buffer,buf_length,(struct sockaddr *) &MC_addr,sizeof(MC_addr));  if (rc < 0)   {    printf ("Could not send data\n");    close (sock);    exit (EXIT_FAILURE);  }  return(0);}/* receive data from the MC *****************************************************//* buffer points to the memory for the received data *//* max BUFFERSIZE bytes can be received *//* returns number of bytes received */int receive_data(char *buffer){  int rc,MC_addr_length;  MC_addr_length = sizeof(MC_addr);  rc = recvfrom (sock,BUFFERSIZE,&MC_addr_length);  if (rc < 0)   {    printf ("Could not receive data\n");    close (sock);    exit (EXIT_FAILURE);  }  return(rc);}
解决方法 在看到有关SO_BINDTODEVICE实际使用的冲突答案后,我一直在研究这段时间. Some sources声称正确的用法是传递一个结构体ifreq指针,它具有通过ioctl获得的设备名称和索引.例如:
struct ifreq ifr;memset(&ifr,sizeof(struct ifreq));snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"eth0");ioctl(fd,SIocgIFINDEX,&ifr);setsockopt(fd,(voID*)&ifr,sizeof(struct ifreq));

其中Beej’s networking tutorial表示将设备名称作为char指针传递.例如:

char *devname = "eth0";setsockopt(fd,devname,strlen(devname));

我已经尝试了这两种方法,并且都做了所需的工作,但是我想注意到,在第一种方法中获得的设备索引是多余的.如果您查看net/core/sock.c中的内核代码,sock_bindtodevice只需复制设备名称字符串,调用dev_get_by_name_rcu即可获取设备并绑定到该设备.

第一种方法的原因是设备名称是ifreq结构中的第一个元素,请参见http://linux.die.net/man/7/netdevice.

总结

以上是内存溢出为你收集整理的SO_BINDTODEVICE Linux套接字选项问题全部内容,希望文章能够帮你解决SO_BINDTODEVICE Linux套接字选项问题所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/1045387.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-24
下一篇 2022-05-24

发表评论

登录后才能评论

评论列表(0条)

保存