2014-05-06 78 views
0

对于类项目,我们被指示使用Winsock2创建简单的程序。我创建了一个开始的回声程序,现在我试图实现一种方法,让程序在一个房间内找到主机本身。该房间位于专用网络192.168.xxx.xxx上,子网数量增加10个,并且可以运行服务器的计算机在每个子网上都是数字50,51和52。我打算做一个简单的实现,只是试图连接到每台计算机,如果可以的话,它就是服务器。不是最好的解决方案,但它仍然使用Winsock2,它适用于我。使用Winsock2和C缩短TCP连接的等待时间

SOCKET connectsock(const char *host, const char *service, const char *transport) 
{ 
struct hostent *phe; /* pointer to host information entry */ 
struct servent *pse; /* pointer to service information entry */ 
struct protoent *ppe; /* pointer to protocol information entry*/ 
struct sockaddr_in sin; /* an Internet endpoint address  */ 
int s, type; /* socket descriptor and socket type */ 

while (1) 
{ 
    memset(&sin, 0, sizeof(sin)); 
    sin.sin_family = AF_INET; 

    /* Map service name to port number */ 
    if (pse = getservbyname(service, transport)) 
     sin.sin_port = pse->s_port; 
    else if ((sin.sin_port = htons((u_short)atoi(service))) == 0) 
     errexit("can't get \"%s\" service entry\n", service); 

    /* Map host name to IP address, allowing for dotted decimal */ 
    if (phe = gethostbyname(host)) 
     memcpy(&sin.sin_addr, phe->h_addr, phe->h_length); 
    else if ((sin.sin_addr.s_addr = inet_addr(host)) == INADDR_NONE) 
     errexit("can't get \"%s\" host entry\n", host); 

    /* Map protocol name to protocol number */ 
    if ((ppe = getprotobyname(transport)) == 0) 
     errexit("can't get \"%s\" protocol entry\n", transport); 
    /* Use protocol to choose a socket type */ 
    if (strcmp(transport, "udp") == 0) 
     type = SOCK_DGRAM; 
    else 
     type = SOCK_STREAM; 

    /* Allocate a socket */ 
    s = socket(PF_INET, type, ppe->p_proto); 
    if (s == INVALID_SOCKET) 
     errexit("can't create socket: %d\n", GetLastError()); 

    /* Connect the socket */ 

    if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR) 
    { 
     printf("can't connect to %s.%s: %d\n", host, service, GetLastError()); 
     host = "localhost"; 
    } 
    else 
     break; 
} 
return s; 

} 

这个循环工作正常,并简单地连接到第一个IP地址,192.168.10.50,然后如果它拉一个错误,连接到一个主机,如果另一个错误,它会尝试第三主机,所以等等,直到它连接成功。由于我仍然只测试程序,我只是重定向到第一次失败后连接到本地主机。

它的工作原理完全正确,唯一的问题是在课堂上,没有延迟。因此,如果有的话,连接会发生十分之一秒。默认情况下,程序将尝试连接到第一台计算机,但无法进入,但在切换到下一个主机之前,它会等待5秒钟并等待响应。

由于这是一个封闭的互联网内的小规模计划,我应该没有任何问题,等待时间缩短到半秒钟,但我的问题是如何?

是否有可能,如果没有,我该怎么做才能纠正它?有没有更高效的方法让主机找到可以移动的服务器?服务器将更换电脑。

+0

您可以将您的请求并行化为大量线程池,也可以使用非阻塞套接字。使用非阻塞套接字,您可以尝试在单个线程中连接,跟踪您创建的所有SOCKET,然后在一两秒钟后查找有效SOCKET。 – Kaslai

+0

所以你认为我应该开始像3线程左右,每个尝试不同的地址? 非阻塞套接字如何?你能给我更多的信息吗? – Brian5193

+0

在SOCKET上使用'ioctlsocket'可以用来更改套接字属性。 'u_long iMode = 1; ioctlsocket(Socket,FIONBIO和iMode);'将使套接字非阻塞,其中'Socket'是你的SOCKET对象。非阻塞套接字操作只是立即返回,因此您可以使用打开但不完整的连接填充SOCKET数组。 – Kaslai

回答

0

如果您使用非阻塞套接字,您应该可以使用单线程有效地进行扫描。为了做到这一点,你可以使用ioctlsocket()函数。

您可以相当容易地将它转换为您的connectsock()函数。如果你在你的socket()connect()调用之间滑动这段代码,它应该做的伎俩。

static u_long iMode=1; 
ioctlsocket(s,FIONBIO,&iMode); 

这将使所有由connectsock()创建的套接字变为非阻塞。这意味着这些套接字上的所有操作都将立即返回,无论是否有数据等待读取或写入。

您可以根据需要启动尽可能多的connectsock()调用,并且只需跟踪所有在阵列中创建的套接字。如果您尝试立即读取或写入套接字,则尝试可能会失败。如果您等待几毫秒,套接字可能会建立并尝试成功。然后,您可以通过任何可以返回错误代码的winsock函数运行它们,并且如果错误代码不是SOCKET_ERROR,那么这应该表示在该套接字的另一侧有一个客户端。