2014-02-19 41 views
1

我正在构建一个UDP服务器来处理飞行模拟器中的位置更新(因此,数据包将会很快并且不需要保证交付)。服务器根据服务器中的“会话”创建并绑定UDP套接字。服务器然后将来自主人的位置信息传送给观众。这个逻辑在我的局域网上(我在同一个系统上测试过服务器和客户端的设置)起作用(尽管我现在把它编码为回送发送给发件人的所有消息,用于测试)。C++ UDP双向客户端/服务器交付

当我将它移动到WAN时,客户端不再能够从服务器接收消息,但服务器收到来自客户端的消息。恐怕这是一个防火墙/端口阻塞问题,但是,我来到这里是希望找到一种不同的/正确的方式来做我正在做的事情,或者说明我如何才能避免阻塞。

服务器的代码如下:

user newuser; 
ommand = raw_connections[i].sockfd;  
sockaddr_in sin; 
socklen_t len = sizeof(sin); 
getsockname(raw_connections[i].sockfd, (sockaddr*)&sin, &len); //raw_connections is a vector of sockets that haven't yet authenticated 
newuser.addr.sin_addr = sin.sin_addr; 
newuser.addr.sin_family = sin.sin_family; 
newuser.addr.sin_port = atoi(inp[4].c_str()); //the UDP port as specified by the client 
flights[fpos].users.push_back(newuser); //fpos is the index in the vector 

上述数据被称为我的程序的UI和系统之间的TCP套接字的结果(该部分将处理用户列表,管理

: - 等的UDP端口从位置系统,该系统如下:)

sockaddr_in service1; 
service1.sin_family = AF_INET; 
service1.sin_addr.s_addr = INADDR_ANY; 
service1.sin_port = htons(0); 

server_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 

mode = 1; 
ioctlsocket(server_sock, FIONBIO, &mode); 

soreuse = 1; 
ioctlsocket(server_sock, SO_REUSEADDR, &soreuse); 


sockaddr_in sin; 
socklen_t len = sizeof(sin); 
getsockname(server_sock, (sockaddr*)&sin, &len); 
udpport = sin.sin_port; //the value of UDP port here is what's given to the client, and ultimately, the server 

服务器的发送部是这样产生它提供给它10

最后,在客户端的交互是这样的:

char* buffer = new char[1024]; 
int recvd = recvfrom(server_sock, buffer, 1024, NULL, (sockaddr*)&server_addr, &sockaddrsize); 
if (recvd > 0) { 
    int i = 282; 
} 
delete[] buffer; 
sendto(server_sock, "test\0", 5, NULL, (sockaddr*)&server_addr, sockaddrsize); 

任何建议,以得到它的工作? (声明的无用变量被用作Visual Studio中的断点。)

回答

1

很可能您的客户端受阻止来自Internet的传入UDP数据包的防火墙保护。为了解决这个问题,你可以指导客户端的系统管理员在服务器发送数据包的端口上手动打开防火墙上的UDP端口(如果涉及到NAT,他们需要设置端口 - 也可以在NAT上进行转发),或者您可以调查UDP hole-punching techniques

但是,上述两种技术都不是特别优雅或健壮的,因此您可能只想为软件提供一种后退模式,即所有数据均通过TCP流传输。性能不会很好,但有时最好让它“正常工作”,TCP将允许这样做。

+0

然而,我害怕这样做,是不是防火墙传统上应该允许从它发送的端口上接收数据? –

+0

我不认为防火墙允许什么官方行为,所以它将取决于它是什么类型的防火墙以及它当前正在运行的设置。请参阅Wikipedia链接中的一些文章,了解哪些规则集是常见的细节,但请注意,您不能依赖任何特定的防火墙来遵循“常规”规则,因此即使您打孔如果你想在任何地方工作,你需要一个后备模式。 –

+0

Aarrggh!困扰我的是,UDP数据包传输对此更有效率...... –

0

首先,你的措辞很混乱:“UDP服务器”“查看器”“客户端”“系统”“位置系统”......。你写道:“我现在编写了它,以便将发送给它的每条消息都回送给发件人进行测试。”但是,您的“客户端”代码仅回答固定字符串"test\0"

如果您有任何疑问,您应该写一个与您的主项目分开的最小测试代码。

我假设“查看者”是“客户端”。“

你写

服务器的发送部分是这样的:

int recvdf = recvfrom(gp->data_socket, ...); 
for (unsigned i = 0; i < sz; i++) { 
    sendto(gp->data_socket, ..., (sockaddr*)&gp->users[i].addr ...); 
} 

最后,在客户端的交互是这样的:

int recvd = recvfrom(server_sock, ...); 
sendto(server_sock, "test\0", ... (sockaddr*)&server_addr, ...); 

但你也回答@Jeremy

我害怕的是,但是,是不是传统上应该允许它从发送端口上接收数据在防火墙?

这两者之间存在矛盾。您的服务器首先将UDP数据报发送给客户端,然后客户端回应。您的服务器和客户端之间的第一个数据包是从服务器发送的。这就是我从你的代码中了解到的。您已经知道这不适用于典型的防火墙。

虽然@Jeremy是正确的,因为每个防火墙的配置不同,大多数(家庭使用)防火墙都能满足您的假设。我怀疑你的代码没有使用普通防火墙的典型行为。例如,如果您的“客户端”端可以使用Windows Internet时间同步,它实际上是一个UDP SNTP客户端,并将UDP数据报从临时源端口发送到时间服务器,则您应该能够从服务器接收UDP数据报,如好。