2016-01-23 37 views
0

我正在編寫大學項目,涉及使用POSIX套接字和C++編寫聊天客戶端和服務器。POSIX UDP套接字未綁定到正確的IP

客戶端應該使用P2P進行對話,例如每個客戶端都有自己的開放UDP套接字,通過該套接字他可以發送消息並從其他客戶端接收消息。

我的問題是2倍:

  1. 我UDPSocket類構造似乎被完全忽視的端口號,而不管參數的綁定到端口65535。
  2. 端口綁定到IP 255.255.255.255而不是我自己的IP(10.0.0.3),或者至少這就是我在調用getpeername時得到的結果。

據我路過INADDR_ANY應綁定到我的本地地址,並通過端口號爲0應該讓OS選擇自由港的知識,我究竟做錯了什麼?

這是我UDPSocket類的構造函數:

UDPSocket::UDPSocket(int port){ 
socket_fd = socket (AF_INET, SOCK_DGRAM, 0); 

// clear the s_in struct 
bzero((char *) &in, sizeof(in)); /* They say you must do this */ 

//sets the sin address 
in.sin_family = (short)AF_INET; 
in.sin_addr.s_addr = htonl(INADDR_ANY); /* WILDCARD */ 
in.sin_port = htons((u_short)port); 

fsize = sizeof(from); 

//bind the socket on the specified address 
if(bind(socket_fd, (struct sockaddr *)&in, sizeof(in))<0){ 
    perror ("Error naming channel"); 
} 
} 

這是初始化:

m_Socket = new UDPSocket(0); 

這是我用來檢索綁定的地址的方法:(UDPSocket繼承插座)

std::string Socket::GetSocketAddress() 
{ 
    struct sockaddr_in addr; 
    int len = sizeof(addr); 
    getpeername(socket_fd, (struct sockaddr*)&addr, (socklen_t*)&len); 

    char ipAddressBuffer[50]; 
    memset(ipAddressBuffer, 0, sizeof(ipAddressBuffer)); 
    sprintf(ipAddressBuffer, "%s:%d", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 

    return ipAddressBuffer; 
} 

任何幫助將不勝感激,Avi。

回答

2

您正在使用getpeername,它爲您提供連接套接字的遠程地址。如果你檢查getpeername()的返回值,它應該指示失敗。

  • 您需要使用getsockname()代替getpeername(),以獲得當地的插座
  • 的您需要檢查getsockname()的地址成功。

請注意,您的套接字綁定到特殊的0.0.0.0地址,這意味着「所有本地接口」,這就是getsockname()也會返回。

+0

感謝(非常)快速響應,雖然現在我面對你似乎已經預測 - 地址是0.0.0.0而不是我自己的地址(本例中爲10.0.0.3)。我如何綁定到我的本地IP地址? –

+1

你需要嗎?綁定到0.0.0.0將允許您在任何地方發送和接收數據包。 – nos

+0

它將如何工作?假設我有兩臺不同的PC上有我的服務器和兩個客戶端A和B,如果我給客戶端一個客戶端B的地址是「0.0.0.0:3456」,他將能夠發送消息到該地址併到達客戶端B? –

0

回答更普遍的問題:「如何建立對等網絡通信與UDP」:

使用UDP套接字,而你可以使用connect,你通常不希望,因爲這限制了你到每個套接字一個對等端。相反,您希望在系統調用sendtorecvfrom的每個對等體中使用單個未連接的UDP套接字,以便爲每個數據包發送和接收具有不同地址的數據包。

sendto函數需要一個數據包和一個對等地址來發送它,而recvfrom函數返回一個數據包和它來自的對等地址。使用一個插座,無需與selectpoll進行復用 - 您只需撥打recvfrom即可從任何來源獲取下一個數據包。當你得到一個數據包時,你也可以得到對方地址來發送數據包(返回)。

在啓動時,您的對等體將創建一個套接字並將其綁定到INADDR_ANY(允許它在計算機上的任何接口或廣播地址上接收數據包)以及分配給您的程序或端口0的特定端口(允許操作系統挑選任何未使用的端口)。在後一種情況下,您需要使用getsockname來獲取端口並將其報告給用戶。一旦套接字建立,對等程序可以sendto任何它知道的對等,或recvfrom任何對等(包括它還不知道)。

所以唯一棘手的部分是引導 - 獲取第一個數據包流動,以便同行可以接收它們並找出它們的對等地址進行通信。一種方法是在啓動每個對等體時在命令行上指定對等地址。你會開始第一個沒有參數(因爲它沒有同齡人 - 但)。它只會recvfrom(在套接字設置後)從同伴獲取數據包。從第一個地址開始,作爲參數。它向第一個對等體發送一個或多個數據包,然後一旦它獲得第一個數據包,它就會知道新的對等體。現在開始第三個客戶端的命令行上的前兩個地址...

+0

感謝您的答案,它似乎適合更一般的情況下,雖然在我的具體情況並不多。 –