我正在尝试使用C ++ winsockets。我想创建一种方法,我可以在网络上找到服务器,而不知道它的IP。为此,我只需通过IP地址192.168.1.0将我的connect方法循环到192.168.1.255。但是,每次连接之间的时间非常长,程序往往会在:connect(nBytes,(sockaddr *)& server,sizeof(server))语句中等待至少30秒(如果不是更长时间)。我的问题如下:为什么会发生这种情况,我该如何解决这个问题?是否有完全不同的,更好的方法来查找服务器?
我的连接方法:
SOCKET connect(char *ipAdress)
{
WSAData wsaData;
if ((WSAStartup(MAKEWORD(2, 2), &wsaData)) == SOCKET_ERROR)
return errorReport("Could not create startup struct");
nBytes = socket(AF_INET, SOCK_STREAM, 0);
if (nBytes == SOCKET_ERROR)
return errorReport("Socket could not be created");
struct hostent *host_entry;
if ((host_entry = gethostbyname(ipAdress)) == NULL)
return errorReport("Cannot find server.");
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(1337);
server.sin_addr.s_addr = *(unsigned long*) host_entry->h_addr;
if (connect(nBytes, (sockaddr*)&server, sizeof(server)) == SOCKET_ERROR)
{
WSACleanup();
return errorReport("Failed to connect to server.");
}
if (nBytes == -1)
{
WSACleanup();
disconnect(nBytes);
return errorReport("Could not connect");
}
return 0;
}
另外,请随时告诉我在当前的连接方法中我做错了什么。
答案 0 :(得分:3)
长时间延迟是由套接字在返回呼叫者之前需要超时引起的。要减少总执行时间,您应该使多个工作线程同时连接到不同的IP地址。
答案 1 :(得分:3)
首先,连接设计为在服务器繁忙时超时之前等待一点。你可以调整超时长度,虽然我不记得究竟如何做到这一点。
其次,您的代码会找到一个服务器,但您怎么知道它是您正在寻找的服务器?它可能是一些其他应用程序只是在同一个端口上侦听。除非您只是对任何服务器进行扫描,否则您需要进行一些验证以确定您在另一端与谁通话。
最后,假设您正在编写客户端和服务器,更好的解决方案是让客户端发送广播/多播消息并让服务器(或服务器,如果有多个)监听并响应对那条消息。然后,客户端只需等待一段指定的时间来响应,以确定服务器的位置。
答案 2 :(得分:1)
我会研究一下winsock是否支持异步I / O.
答案 3 :(得分:1)
服务器IP地址是如此随机,您每次都需要这样做吗?我没有在很长一段时间内完成任何套接字编程,但是如果超时,这样可能不会好多了。
其他选择:
答案 4 :(得分:0)
如果您知道服务器在子网上,为什么不发送带有本地接收端口号的广播消息作为消息数据?然后,服务器可以简单地监听此消息并连接回该端口,或将其自己的配置数据发送回该端口,以便客户端可以直接连接。这样,您只需要发送一条消息而不是循环超过256个IP地址。
答案 5 :(得分:0)
过去我在“每个人都有139个开放日”的回归中取得了巨大的成功。
我发现使用多个线程(可悲的是,我使用了大约500个,但这只是一次性拍摄而且只是为了好玩)我在尝试连接之前ping了服务器,允许我每秒遍历几个IP和IP。
我还有源代码(C ++),如果您想查看它,只留下一条消息。
另外,为什么有必要扫描IP?即使它是动态的,你也应该能够通过它的主机名来查看ip。请参阅gethostbyname()或getaddrinfo()。
答案 6 :(得分:0)
我看到你正在使用Windows。但是如果你使用Linux,你可以通过组合非阻塞套接字并选择:
来创建一个超时的连接函数。int connect_with_timeout(int sock, struct sockaddr *addr, int size_addr, int timeout) {
#if defined(Linux)
int error = 0;
fd_set rset;
fd_set wset;
int n;
// set the socket as nonblocking IO
int flags = fcntl (sock, F_GETFL, 0);
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
errno = 0;
// we connect, but it will return soon
n = connect(sock, addr, size_addr);
if(n < 0) {
if (errno != EINPROGRESS) {
return -1;
}
} else if (n == 0) {
goto done;
}
FD_ZERO(&rset);
FD_ZERO(&wset);
FD_SET(sock, &rset);
FD_SET(sock, &wset);
struct timeval tval;
tval.tv_sec = timeout;
tval.tv_usec = 0;
// We "select()" until connect() returns its result or timeout
n = select(sock + 1, &rset, &wset, 0, timeout ? &tval : 0);
if(n == 0) {
errno = ETIMEDOUT;
return -1;
}
if (FD_ISSET(sock, &rset) || FD_ISSET(sock, &wset)) {
socklen_t len = sizeof(error);
if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
return -1;
}
} else {
return -1;
}
done:
// We change the socket options back to blocking IO
if (fcntl(sock, F_SETFL, flags) == -1) {
return -1;
}
return 0;
#else
return connect(sock, addr, size_addr);
#endif
}