C - 获取地址信息 returns "Servname not supported for ai_socktype"

C - getaddrinfo returns "Servname not supported for ai_socktype"

所以,在我得到这个错误之后,我一直在这里寻找答案,几乎每个人都有一个困难的方法来修复这个错误但是没有人解释为什么会出现这个错误,所以我没有发现这个问题完全重复。

我用 C 编写了一个 TCP 套接字,我使用 "getaddrinfo" 函数使套接字与主机名一起工作,它工作得很好!你可以在 github.

上找到我的代码

但是当我试图通过 "getaddrinfo" 创建一个 UDP socket 时,我得到了这个错误:
ai_socktype

不支持服务名称

client.c

const char *host = argv[1];
const char *service = argv[2];
const char *string = argv[3];

struct addrinfo addrCriteria;
memset(&addrCriteria, 0, sizeof(addrCriteria));
addrCriteria.ai_family = AF_UNSPEC;
addrCriteria.ai_socktype = SOCK_DGRAM;
addrCriteria.ai_protocol = IPPROTO_UDP;

struct addrinfo *servAddr;
int ret = getaddrinfo(host, service, &addrCriteria, &servAddr);
if(ret != 0)
    sysError(gai_strerror(ret));

我意识到当我给 "service" 一个像 8080 这样的数字输入时,不会有错误 return 但是当我使用一个字符串作为服务名称时 "tproxy" 指向 port/8081, 'gai_strerror' returns 提到的错误。

显然,gai_strerror 表示:"service names not supported for 'SOCK_DGRAM' socket types",但为什么呢?我的意思是 "getaddrinfo" 不支持通过 UDP 套接字提供名称服务的确切原因?
有没有其他方法可以使用带有 UDP 套接字的服务名称而不是端口号?怎么样?

当为 service 参数指定非数字值时,将在 /etc/services 文件中查找(在 Linux 上)。此文件将服务名称映射到 port/protocol。以下是一些示例条目:

ssh             22/tcp  
telnet          23/tcp
domain          53/tcp                          # name-domain server
domain          53/udp

您收到错误的原因是您的 /etc/services 文件中没有 "tproxy" 的 UDP 条目。查看此文件并查找确实指定 UDP 端口的条目,例如 "domain"。那应该有 53/tcp 和 53/udp 的条目。如果您传入 "domain" 作为服务名称,您应该会返回一个结果。

TL;DR: 没有 tproxy UDP 端口。


如果您在服务数据库中查找 tproxy UDP 套接字服务,

getent services tproxy/udp

您没有得到任何输出,因为 tproxy 不是 UDP 服务。如果您查看所有 tproxy 服务而不考虑协议 getent services | grep -e tproxy,您会看到

tproxy    8081/tcp

表示tproxy服务仅为TCP协议定义。

这意味着如果您向 getaddrinfo() 请求服务 8081 的 UDP 套接字,您将找不到任何东西,因为 tproxy 只为 TCP 而不是 UDP 定义。

与您请求 xmpp-client 服务的 UDP 套接字的情况相比。至少我的服务数据库 (getent services xmpp-client/udp) 响应

xmpp-client           5222/udp jabber-client

事实上,getaddrinfo() 很乐意为此类 UDP 套接字提供套接字描述(使用 xmpp-clientjabber-client 作为服务)。

因此,像 xmpp-client 这样的服务确实同时定义了 TCP 和 UDP 端口。在我的系统上,getent services | grep -e xmpp-client 显示

xmpp-client           5222/tcp jabber-client
xmpp-client           5222/udp jabber-client

因为 TCP 和 UDP 是基于 IP 的不同协议,所以服务可以使用不同的端口号进行 TCP 和 UDP 通信是有道理的。因此,假定服务数据库应该 return TCP 和 UDP 套接字的相同端口号是不合理的。

换句话说,您遇到错误是因为您错误地认为因为某些服务使用 TCP 端口,并且在服务数据库中注册了名称,您应该能够使用该名称来指定 UDP 端口号,也是。

TCP和UDP是不同的协议,它们的端口号空间是分开的。例如,Unix exec r-服务使用 TCP 端口 512,而 biff 邮件通知服务使用 UDP 端口 512。