微控制器具有非常简单的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); }
解决方法
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.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。