2016-01-23 97 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

感谢您的答案,它似乎适合更一般的情况下,虽然在我的具体情况并不多。 –