高分求教:recvfrom函数使用的问题
Linux系统,有多个网卡(即有多个IP地址)基于UDP协议的SOCKET编程中,创建了一个sock=socket(AF_INET,SOCK_DGRAM,0);绑定该sock的端口为5060,不指定该sock的IP地址。然后用recvfrom(sock,buff,500,0,(struct sockaddr *)&source,&i)接收数据。有什么办法可以知道数据是由本机的哪个IP接收呢。我用了getsockname和getpeername函数,返回的结果都不对,两个函数的返回值都是-1。请各位指教,谢谢了!
我的代码如下:
-----------------------
int main()
{
int sock,i;
char buff[100];
struct sockaddr_in address,ad,source;
address.sin_family=AF_INET;
address.sin_port=htons(5678);
address.sin_addr.s_addr=inet_addr( "0.0.0.0 ");
sock=socket(AF_INET,SOCK_DGRAM,0);
bind(sock,(struct sockaddr *)&address,sizeof(address));
source.sin_family=PF_INET;
ad.sin_family=PF_INET;
recvfrom(sock,buff,500,0,(struct sockaddr *)&source,&i);
if(getsockname(sock,(struct sockaddr *)&ad,&i))
{
puts( "Error! ");
}
close(sock);
--------------
以上代码,在没有recvfrom(sock,buff,500,0,(struct sockaddr *)&source,&i);一行时还可以正常运行,一加上这一句,getsockname函数就返回错误值。
[解决办法]
http://www.opengroup.org/onlinepubs/007908799/xns/recvfrom.html
[解决办法]
在linux内核中,一个socket有两个地址,一个本地地址,一个外部俩接地址,
如果使用udp协议,
在调用bind函数时,会把你要绑定的那个地址填到socket的本地地址那块地方.你要设成0.0.0.0它就给你填成0.0.0.0
在udp使用bind函数只是为了不用每此发送数据都填充地址这一参数传递过程而已.
只是在你发送数据时才会根据情况把实际的ip地址填到发送的数据的相应位置.
在内核接收到一个数据包时,会接收到一个外部地址,在你调用读函数时就把此地址读取走了.
如过使用tcp协议时,
在调用bind函数时,会把本地地址填到socket的本地地址那块地方.
在调用connect或则调用accecpt接收到连接时,回把外部地址那块填上.
在读写数据时,只读走数据,不读去地租.
在你这里
主要是 recvfrom(sock,buff,500,0,(struct sockaddr *)&source,&i);
里的i值不确定,也就是说没接收到地址.
[解决办法]
recvfrom(sock,buff,500,0,(struct sockaddr *)&source,&i);
if(getsockname(sock,(struct sockaddr *)&ad,&i))
---------------
这两句的每一句之前加上
i = sizeof(struct sockaddr_in);
[解决办法]
getsockname只能取得绑定的地址,如果在bind中没有显示给出ip,系统有默认的值,getsockname取得的就是这个,达不到你的目的。可以用revmsg函数取得源地址。
用其中的control字段返回。
struct in_pktinfo {
unsigned int ipi_ifindex; /* Interface index */
struct in_addr ipi_spec_dst; /* Local address */
struct in_addr ipi_addr; /* Header Destination address */
};
可参考http://linux.about.com/od/commands/l/blcmdl7_ip.htm