我是否可以使用inet\u pton为我的TCP套接字服务器设置文本地址,如;“设备1.本地”吗;?
我已经用C编写了一个TCP套接字,它需要与通过本地网络连接到此地址的移动应用程序配合使用:“我是否可以使用inet\u pton为我的TCP套接字服务器设置文本地址,如;“设备1.本地”吗;?,c,sockets,tcp,dns,C,Sockets,Tcp,Dns,我已经用C编写了一个TCP套接字,它需要与通过本地网络连接到此地址的移动应用程序配合使用:“device1.local:6666” 我找到的每个使用inet\u pton()设置服务器地址的示例都有一个类似以下内容的IPV4地址:192.168.1.34,或者一个类似以下内容的IPV6地址:2001:db8:8714:3a90::12。如果我想让客户端远程登录到“device1.local”而不是数字或十六进制地址,我应该指定哪种格式?如何设置TCP套接字服务器以应答该地址 这不起作用: loc
device1.local:6666
”
我找到的每个使用inet\u pton()
设置服务器地址的示例都有一个类似以下内容的IPV4地址:192.168.1.34
,或者一个类似以下内容的IPV6地址:2001:db8:8714:3a90::12
。如果我想让客户端远程登录到“device1.local
”而不是数字或十六进制地址,我应该指定哪种格式?如何设置TCP套接字服务器以应答该地址
这不起作用:
local_socket = socket(AF_INET6, SOCK_STREAM, 0);
if(local_socket < 0) {
printf("unable to create socket\n");
return false;
}
printf("socket created\n");
bzero((void *)&server_address, sizeof(server_address));
server_address.sin6_family = AF_INET6;
int s_code = inet_pton(AF_INET6, "device1.local", &server_address.sin6_addr);
server_address.sin6_port = htons(port_number);
printf("inet_pton returned: %d\n", s_code);
char str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &server_address.sin6_addr, str, INET6_ADDRSTRLEN);
printf("address from inet_ntop(): %s\n", str);
我意识到我可能对互联网(或本地网络)的工作方式缺乏基本的了解。任何相关的链接,你可以给我,让我可以了解更多关于如何自定义文本地址的工作将不胜感激
如果我想让我的客户端远程登录到“device1.local”而不是数字或十六进制地址,我应该指定哪种格式
inet\u pton()。您不能使用它将主机名解析为IP地址。为此,您需要使用gethostbyname()
(不推荐使用)或getaddrinfo()
(首选)
下面是一个gethostbyname()
示例:
int connect_to_addr(const sockaddr *addr, int addrlen)
{
local_socket = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (local_socket == -1)
{
printf("unable to create socket\n");
return -1;
}
char str[INET6_ADDRSTRLEN];
unsigned short port;
switch (addr->sa_family)
{
case AF_INET:
{
struct sockaddr_in *saddr = (struct sockaddr_in*)addr;
inet_ntop(AF_INET, &(saddr->sin6_addr), str, sizeof(str));
port = ntohs(saddr->sin_port);
break;
}
case AF_INET6:
{
struct sockaddr_in6 *saddr = (struct sockaddr_in6*)addr;
inet_ntop(AF_INET6, &(saddr->sin6_addr), str, sizeof(str));
port = ntohs(saddr->sin6_port);
break;
}
}
printf("connecting to address: %s on port: %hu\n", str, port);
if (connect(local_socket, addr, addrlen) != 0)
{
printf("unable to connect\n");
close(local_socket);
local_socket = -1;
return 0;
}
printf("connected\n");
return 1;
}
int connect_to_addr(const sockaddr *addr, int addrlen)
{
local_socket = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (local_socket == -1)
{
printf("unable to create socket\n");
return -1;
}
char str[INET6_ADDRSTRLEN];
unsigned short port;
switch (addr->sa_family)
{
case AF_INET:
{
struct sockaddr_in *saddr = (struct sockaddr_in*)addr;
inet_ntop(AF_INET, &(saddr->sin6_addr), str, sizeof(str));
port = ntohs(saddr->sin_port);
break;
}
case AF_INET6:
{
struct sockaddr_in6 *saddr = (struct sockaddr_in6*)addr;
inet_ntop(AF_INET6, &(saddr->sin6_addr), str, sizeof(str));
port = ntohs(saddr->sin6_port);
break;
}
}
printf("connecting to address: %s on port: %hu\n", str, port);
if (connect(local_socket, addr, addrlen) != 0)
{
printf("unable to connect\n");
close(local_socket);
local_socket = -1;
return 0;
}
printf("connected\n");
return 1;
}
下面是一个getaddrinfo()
示例:
int connect_to_addr(const sockaddr *addr, int addrlen)
{
local_socket = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (local_socket == -1)
{
printf("unable to create socket\n");
return -1;
}
char str[INET6_ADDRSTRLEN];
unsigned short port;
switch (addr->sa_family)
{
case AF_INET:
{
struct sockaddr_in *saddr = (struct sockaddr_in*)addr;
inet_ntop(AF_INET, &(saddr->sin6_addr), str, sizeof(str));
port = ntohs(saddr->sin_port);
break;
}
case AF_INET6:
{
struct sockaddr_in6 *saddr = (struct sockaddr_in6*)addr;
inet_ntop(AF_INET6, &(saddr->sin6_addr), str, sizeof(str));
port = ntohs(saddr->sin6_port);
break;
}
}
printf("connecting to address: %s on port: %hu\n", str, port);
if (connect(local_socket, addr, addrlen) != 0)
{
printf("unable to connect\n");
close(local_socket);
local_socket = -1;
return 0;
}
printf("connected\n");
return 1;
}
int connect_to_addr(const sockaddr *addr, int addrlen)
{
local_socket = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (local_socket == -1)
{
printf("unable to create socket\n");
return -1;
}
char str[INET6_ADDRSTRLEN];
unsigned short port;
switch (addr->sa_family)
{
case AF_INET:
{
struct sockaddr_in *saddr = (struct sockaddr_in*)addr;
inet_ntop(AF_INET, &(saddr->sin6_addr), str, sizeof(str));
port = ntohs(saddr->sin_port);
break;
}
case AF_INET6:
{
struct sockaddr_in6 *saddr = (struct sockaddr_in6*)addr;
inet_ntop(AF_INET6, &(saddr->sin6_addr), str, sizeof(str));
port = ntohs(saddr->sin6_port);
break;
}
}
printf("connecting to address: %s on port: %hu\n", str, port);
if (connect(local_socket, addr, addrlen) != 0)
{
printf("unable to connect\n");
close(local_socket);
local_socket = -1;
return 0;
}
printf("connected\n");
return 1;
}
如何设置TCP套接字服务器以应答该地址
您只需将侦听套接字bind()
绑定到服务器计算机本地的特定IP地址(使用getifaddrs()
或等效API获取本地IP列表)。或者使用通配符地址(INADDR\u ANY
用于IPv4,in6addr\u ANY
用于IPv6)绑定到所有可用的本地IP
客户端的DNS查找将负责将设备.local
解析为路由到服务器计算机的IP地址,如果服务器套接字正在该IP上侦听,则它可以接受()
传入连接。.local
TLD为MDN保留,如中所述
因此,要使device.local
正常工作,您的本地系统应设置device
作为主机名,并应运行Bonjour服务(内置于Windows和OSX,在Linux上作为Avahi提供)
完成后,您的服务器端应用程序根本不需要做任何特殊的事情—它只需将绑定到INADDR\u ANY
并在任何接口上接受传入(IPv4)连接
让事情稍微复杂一点的是,如果您也想通过IPv6提供服务,那么通常需要两个侦听套接字,第二个绑定到in6addr\u any
在客户端,getaddrinfo()
函数应该能够连接到MDN,并相应地将名称解析为正确的IP地址。您可以让客户端接受URL(就像web浏览器或telnet客户端一样),但最终,当使用需要它们的套接字API函数时,需要将它们解析为网络地址。你别无选择;底层协议使用地址(即使是虚线地址也不是真实的网络地址,比如URL,它们只是为了方便人类,而不是计算机)。我的客户机接受URL是什么意思?我希望服务器连接到请求地址device1.local
的客户机。然后服务器成为客户机,同样的原则也适用。所谓客户机,我指的是与服务器建立连接的任何进程。服务器也可以是客户端。无论如何,要使用套接字API通过网络连接,必须将名称解析为网络地址。也许我误解了你的问题。也许你可以看看gethostbyname()函数。也许这就是您要找的。gethostbyname()
不推荐使用。改用getaddrinfo()
。我不这么认为。“如果我希望我的客户机将telnet转换为“主机名”而不是数字或十六进制地址,我应该指定哪种格式?”-这就是我的回答,客户机如何将主机名解析为IP,从而连接到该主机。主机名以.local
结尾这一事实与此无关,DNS系统代表客户端处理此问题。在这种情况下,通过gethostbyname()
和getaddrinfo()
进行内部解析。严格来说,是由系统解析程序决定是使用DNS还是/etc/hosts还是MDN(如果名称与本地配置的mDNS域名匹配,则选择后者,默认为.local
)。现在回想起来还不是100%清楚,但OP似乎在问(“我如何设置TCP套接字服务器来回答该地址?”)如何使用inet\u ntop()
选择要绑定的地址,答案是“不要使用INADDR\u ANY
”,这很有用!“让事情稍微复杂一点的是,如果您也想通过IPv6提供服务,那么您通常需要两个侦听套接字,第二个绑定到in6addr\u any
”——除非您使用双堆栈套接字,它可以同时为IPv4和IPv6客户端提供服务。
int connect_to_addr(const sockaddr *addr, int addrlen)
{
local_socket = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
if (local_socket == -1)
{
printf("unable to create socket\n");
return -1;
}
char str[INET6_ADDRSTRLEN];
unsigned short port;
switch (addr->sa_family)
{
case AF_INET:
{
struct sockaddr_in *saddr = (struct sockaddr_in*)addr;
inet_ntop(AF_INET, &(saddr->sin6_addr), str, sizeof(str));
port = ntohs(saddr->sin_port);
break;
}
case AF_INET6:
{
struct sockaddr_in6 *saddr = (struct sockaddr_in6*)addr;
inet_ntop(AF_INET6, &(saddr->sin6_addr), str, sizeof(str));
port = ntohs(saddr->sin6_port);
break;
}
}
printf("connecting to address: %s on port: %hu\n", str, port);
if (connect(local_socket, addr, addrlen) != 0)
{
printf("unable to connect\n");
close(local_socket);
local_socket = -1;
return 0;
}
printf("connected\n");
return 1;
}
bool connect_to_host(const char* hostname, unsigned short port)
{
local_socket = -1;
printf("resolving %s:%hu\n", hostname, port);
struct addrinfo hints;
bzero((void *)&hints, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
char service[6];
bzero(service, sizeof(service));
sprintf(service, "%hu", port_number);
struct addrinfo *addrs = 0;
if (getaddrinfo(hostname, service, &hints, &addrs) != 0)
{
printf("unable to resolve\n");
return false;
}
for(struct addrinfo *addr = addrs; addr != 0; addr = addr->ai_next)
{
if (connect_to_addr((struct sockaddr*)(addr->ai_sockaddr), addr->ai_addrlen) != 0)
break;
}
freeaddrinfo(addrs);
return (local_socket != -1);
}
if (connect_to_host("device.local", 6666))
{
// use local_socket as needed...
close(local_socket);
}