Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
recvfrom函数能否从套接字提取发送方IP地址?_C_Sockets - Fatal编程技术网

recvfrom函数能否从套接字提取发送方IP地址?

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 {

我们知道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 {
            __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;
    ...
}