但当我给它“0”端口时,它在addrinfo结果中保持“0”,这导致每个绑定给我不同的端口号。
我的问题:有没有一种方法告诉getaddrinfo选择一个在所有接口上都是空闲的自由端口,然后将给定的地址绑定到所有接口?
如果没有,有没有其他方法可以找到自由端口号?(不绑定,失败时停止)
#ifdef WIN32
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#define closesocket close
#endif
#include <iostream>
#include <vector>
#include <stdio.h>
#include <string>
int GetAddressFamily()
{
return AF_UNSPEC;
}
std::string ipaddress(addrinfo* info)
{
std::string retval;
char temp[260];
socklen_t addrlen = (socklen_t)info->ai_addrlen;
int res = ::getnameinfo(info->ai_addr, addrlen, temp, 256, NULL, 0, NI_NUMERICHOST);
if(res){
std::cout<<gai_strerrorA(res)<<std::endl;
}else{
retval = temp;
}
return retval;
}
int getport(addrinfo* info)
{
int retval=0;
if (info->ai_family == AF_INET) {
retval = htons(((struct sockaddr_in*)(info->ai_addr))->sin_port);
}else{
retval = htons(((struct sockaddr_in6*)(info->ai_addr))->sin6_port);
}
return retval;
}
int main()
{
char *hostName = NULL; //GetHostName();
int portNum = 0;
#ifdef WIN32
WSADATA w;
if(0 != WSAStartup(MAKEWORD(2, 2), &w))
{
std::cerr<<" WSAStartup() failed \n";
return -1;
}
#endif
addrinfo hints,*results,*tmp;
memset(&hints,0,sizeof(hints));
hints.ai_family = GetAddressFamily();
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
if(hostName){
hints.ai_flags |= AI_CANONNAME;
//AI_CANONNAME - fills ai_cannonname in address.
}else{
hints.ai_flags |= AI_PASSIVE;
//AI_PASSIVE - give ADDR_ANY and IN6ADDR_ANY_INIT when hostName is NULL
}
char portbuff[40];
sprintf(portbuff,"%u",portNum);
int res = ::getaddrinfo(hostName, portbuff,&hints, &results);
if(res){
std::cerr<<gai_strerrorA(res)<<std::endl;
}else{
std::vector<int> sockets;
for(tmp = results; tmp ; tmp=tmp->ai_next){
std::cout<<ipaddress(tmp).c_str()<<" : "<<port(tmp)<<std::endl;
int s = socket(tmp->ai_family,tmp->ai_socktype,tmp->ai_protocol);
if(s != -1){
res = bind(s, tmp->ai_addr, (int)tmp->ai_addrlen);
if(res != -1){
sockaddr_storage addr;
socklen_t len =sizeof(addr);
int res = getsockname(s, (struct sockaddr *)&addr, &len);
std::cout<<"Bound to port: ";
if(addr.ss_family == AF_INET){
std::cout<<htons(((sockaddr_in*)&addr)->sin_port)<<std::endl;
}else{
std::cout<<htons(((sockaddr_in6*)&addr)->sin6_port)<<std::endl;
}
sockets.push_back(s);
}
}
}
for(int i=0;i<sockets.size();i++){
closesocket(sockets[i]);
}
}
::freeaddrinfo(results);
return 0;
}
void setport(addrinfo* info,int port)
{
for(addrinfo* tmp = info; tmp ; tmp=tmp->ai_next){
if (tmp->ai_family == AF_INET) {
((struct sockaddr_in*)(tmp->ai_addr))->sin_port = htons(port);
}else{
((struct sockaddr_in6*)(tmp->ai_addr))->sin6_port = htons(port);
}
}
port = getport(result)
//...after bind:
if(port == 0) {
port = printed value after succesful bind
setport(result, port)
}
我认为您的最佳选择是使用禁用ipv6_v6only
的IPv6套接字。则该单个套接字将同时连接IPv6和IPv4连接。IPv4客户端将地址设置为映射地址::ffff:a.b.c.d
。
这里没有使用getaddrinfo
的理由,因为您没有查找任何内容。类似这样的东西应该可以做到(未经测试):
int s = socket(AF_INET6, SOCK_STREAM, 0);
if (s < 0)
throw std::system_error(errno, generic_category());
const int off = 0;
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)) {
close(s);
throw std::system_error(errno, generic_category());
}
struct sockaddr_in6 addr{};
socklen_t alen = sizeof(addr);
if (bind(s, static_cast<struct sockaddr*>(&addr), alen)) {
close(s);
throw std::system_error(errno, generic_category());
}
getsockname(s, static_cast<struct sockaddr*>(&addr), &alen);
int port = ntohs(addr.sin6_port);
ps.最好总是将ipv6_v6only
选项设置为您希望的任何值,因为默认值在不同的操作系统之间有所不同。
问题内容: 我有一个很奇怪的要求,其中要求我默认在HTML的下拉菜单中没有选择任何选项。然而, 我不能用这个 因为,为此,我将必须进行验证以处理第一个选项。有人可以在没有将第一个选项作为select标签的一部分的情况下帮助我实现此目标吗? 问题答案: 也许这会有所帮助 将默认显示。但是,如果您选择一个选项,则将无法再次选择它。 您也可以通过添加一个空白来隐藏它 因此它将不再显示在列表中。 选项2
问题内容: 我在Java中实现了一个“另存为”对话框,该对话框提示用户是否已存在该文件,并且我希望默认情况下选择“否”选项。我该怎么做呢? 这是我当前的代码: 问题答案: 使用此构造函数: 其中指定按钮,并具有(值之一)指定默认值。 更新: 您可以致电而不是。前者采用和参数。
我尝试在我的程序中使用G1GC。该程序可在各种内存大小的机器上使用:1Gb内存的VPS(最小)、8Gb内存的桌面、32Gb内存的DS(最大)。我注意到G1GC没有保留更多的内存,即使有很多可用内存(例如,G1GC在我的机器上保留的内存不超过3Gb,总共8Gb/4Gb可用) 另外,我想要一个通用的解决方案。我无法为每种类型的机器创建单独的版本或单独的运行脚本。
问题内容: 我想在MS SQL Server 2000中创建一个链接服务器,该服务器在端口x(不是默认端口1433)上运行的MS SQL 2005 Server。但这不起作用,因为我无法在任何地方指定端口! 使用sqlcmd(指定端口x),我可以毫无问题地连接到服务器-但是我无法将其设置为链接服务器。 如何才能做到这一点? 问题答案: 在新的链接服务器对话框中,选择“其他数据源”,选择“ SQL
问题内容: 我已经搜索过Google,但找不到任何东西。 我有这个代码。 有这样的数据 输出是这样的。 如何将数据中的第一个选项设置为默认值,这样您将得到这样的结果。 问题答案: 您可以像这样简单地使用ng-init
我在运行CentOS6.4的三个虚拟机集群上尝试了Hadoop2。 我成功地启动了hadoop集群,尽管hadoop 2的配置文件(如:core-site.xml、hdfs-site.xml、mapred-site.xml和yarn-site.xml)让我感到很痛苦。 我想更改Hadoop2使用的所有默认端口。配置文件的正式文档中定义了如此多的端口号。因此,我认为最好确定Hadoop运行时使用了哪