recvfrom函数能否从套接字提取发送方IP地址?
我们知道Recvfrom函数有以下概要recvfrom函数能否从套接字提取发送方IP地址?,c,sockets,C,Sockets,我们知道Recvfrom函数有以下概要 SYNOPSIS #include <sys/socket.h> int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen); 但sockaddr似乎无法保存IP地址 recvfrom不应该在*from中使用struct socaddr_,因为 struct sockaddr_in {
SYNOPSIS
#include <sys/socket.h>
int recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
但sockaddr似乎无法保存IP地址
recvfrom不应该在*from中使用struct socaddr_,因为
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地址。这是一个有效的假设吗?您可以按照以下步骤进行操作:
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...
出于历史原因,
from
参数被定义为sockaddr*
,以支持IPv6之前的遗留代码sock_addr
是相当不可知的,但它也不足以处理较新的套接字类型。任何具有sockaddr*
参数的套接字函数实际上都期望基于sockaddr
的结构适合所使用的套接字类型
如果从IPv4套接字读取,则在*中需要一个sockaddr\u,例如:
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\u 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\u storage
并根据需要键入cast,例如:
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()
,当您尝试它时发生了什么?我已经列出了struct sockaddr{uu uint8_t sau len;//总长度sau family[XSI]address family char sa_data[14];/[XSI]addr value(实际上更大)};sockaddr没有sin_addr字段。此示例仅适用于IPv4,但不适用于IPv6或任何其他套接字类型(套接字不限于IP协议)。此外,在调用recvfrom
之前,您必须初始化len
,以便它知道A
有多大。recvfrom
如果A
太小而无法接收源地址,则将失败。或者,您也可以使用sockaddr\u存储
结构,该结构保证至少与任何t结构一样大操作系统支持的sockaddr\uu
类型。recvfrom()被定义为ssize\t recvfrom(int sockfd,void*buf,size\t len,int flags,struct sockaddr*src\u addr,socklen\u t*addrlen);
in。最后一个参数是指向socklen\u t结构的指针,我认为您不能直接使用sizeof()。@jaako我修复了它
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;
...
}