2014-05-06 73 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,那麼這應該表示在該套接字的另一側有一個客戶端。