2013-09-25 255 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我修好了 –

相關問題