微控制器具有非常简单的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套接字选项问题所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)