2013-09-25 196 views
1

我们知道recvfrom函数具有以下提要可以从Socket的recvfrom函数中提取发件人的IP地址吗?

SYNOPSIS 
#include <sys/socket.h> 
int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); 

的从具有的sockaddr的结构。

struct sockaddr { 
       __uint8_t sa_len;  // total length 
       sa_family_t sa_family; // [XSI] address family 
       char  sa_data[14]; // [XSI] addr value (actually larger) 
      }; 

但sockaddr似乎无法保存IP地址。

不宜recvfrom的是使用结构socaddr_in *从因为

 struct sockaddr_in { 
      __uint8_t sin_len; 
      sa_family_t sin_family; 
      in_port_t sin_port; 
      struct in_addr sin_addr; 
      char  sin_zero[8]; 
     }; 

而sin_addr会给IP地址。这是一个有效的假设吗?

+0

当你尝试过时发生了什么? – EJP

回答

0

您可以进行如下操作:

struct scokaddr_in A; 
char buf[200]; 
int len; 
recvfrom(fd, buf, 200, 0, (struct sockaddr*)&A, &len); 
//from ip-address is stored in A.sin_addr... 
+0

那么,我已经列出struct sockaddr {__ __uint8_t sa_len; //总长度 sa_family_t sa_family; // [XSI]地址族 char sa_data [14]; // [XSI]地址值(实际上较大) }; sockaddr没有sin_addr字段。 – lilzz

+0

本示例仅适用于IPv4,但不适用于IPv6或其他任何套接字类型(套接字不仅限于IP协议)。另外,你必须在调用'recvfrom'之前初始化'len',以便知道'A'的大小。如果'A'太小而无法接收源地址,'recvfrom'将会失败。 –

4

from参数定义为sockaddr*由于历史原因,以支持IPv6的早遗留代码。 sock_addr是相当不确定的,但它也不足以处理较新的套接字类型。任何具有sockaddr*参数的套接字函数实际上都期望基于sockaddr的结构适用于正在使用的套接字类型。

如果从IPv4套接字读取,它需要一个sockaddr_in*,如:

struct sockaddr_in from; 
socklen_t len = sizeof(from); 
recvfrom(s, ..., (struct sockaddr*)&from, &len); 
// use from.sin_addr and from.sin_port as needed... 

如果从IPv6套接字读取,它需要一个sockaddr_in6*代替,例如:

struct sockaddr_in6 from; 
socklen_t len = sizeof(from); 
recvfrom(s, ..., (struct sockaddr*)&from, &len); 
// use from.sin6_addr and from.sin6_port as needed... 

如果你想编写支持多种协议的代码,根据需要使用sockaddr_storage并进行类型转换,例如:

struct sockaddr_storage from; 
socklen_t len = sizeof(from); 
recvfrom(s, ..., (struct sockaddr*)&from, &len); 
switch (from.ss_family) 
{ 
    case AF_INET: 
     // use ((struct sockaddr_in*)&from) as needed... 
     break; 
    case AF_INET6: 
     // use ((struct sockaddr_in6*)&from) as needed... 
     break; 
    ... 
} 

这同样适用于其他基于sockaddr的功能,包括connect(),bind(),accept()sendto()

+0

或者,您也可以使用'sockaddr_storage'结构,该结构保证至少与操作系统支持的任何'sockaddr_ '类型一样大。 –

+0

recvfrom()被定义为'ssize_t recvfrom(int sockfd,void * buf,size_t len,int flags,struct sockaddr * src_addr,socklen_t * addrlen);'在https://linux.die.net/man/2/ recvfrom的。最后一个参数是一个指向socklen_t结构的指针,我不认为你可以直接使用sizeof()。 – Jaakko

+0

@Jaakko我修好了 –

相关问题