简体   繁体   English

C++ 客户端套接字从端口发送更改与发送更改?

[英]C++ client socket send from port change with send to change?

I have a UDP based server/client application where on initial communication, the client sends a message to the server (on specific IP/port), then the server replies with a new port to talk to.我有一个基于 UDP 的服务器/客户端应用程序,在初始通信时,客户端向服务器发送一条消息(在特定的 IP/端口上),然后服务器回复一个新的端口来与之交谈。 The client then sends another message to the new port (same server IP as before), and communications normally continue from there.然后客户端向新端口发送另一条消息(与以前相同的服务器 IP),通信正常从那里继续。 I've had a couple complaints about this communication failing, but I haven't been able to reproduce it.我有几个关于这种通信失败的投诉,但我无法重现它。 The logs I have don't contain as much as I'd like, but I can see that when the issue occurs, the 2nd thread on the server that receives the 2nd message drops it because the client IP/port is unknown (the first thread logs it for the 2nd thread prior to replying to the client, mutexes and everything look correct for ensuring the data is there before the 2nd thread gets the next message).我拥有的日志没有包含我想要的那么多,但我可以看到,当问题发生时,接收第二条消息的服务器上的第二个线程将其丢弃,因为客户端 IP/端口未知(第一个线程在回复客户端之前为第二个线程记录它,互斥体和一切看起来都是正确的,以确保在第二个线程收到下一条消息之前数据就在那里)。

This works fine every time I've tested it, and I know the assumption is that the first message from the client comes from the same IP/port as the 2nd message, which I unfortunately do not have logs to verify whether or not that was the case and I'm starting to wonder if that assumption is incorrect based on the client code.每次我测试它都可以正常工作,而且我知道假设来自客户端的第一条消息来自与第二条消息相同的 IP/端口,不幸的是我没有日志来验证这是否是这种情况下,我开始怀疑基于客户端代码的假设是否不正确。 Here's the client code (windows):这是客户端代码(Windows):

SOCKET skt = socket(AF_INET, SOCK_DGRAM, 0);
std::string serverAddr("127.0.0.1");
int addrInt = inet_addr(serverAddr.c_str());
sockaddr_in toAddr;
toAddr.sin_family = AF_INET;
toAddr.sin_addr.s_addr = addrInt;
toAddr.sin_port = htons(12345);
uint8_t txBuf[] msg = "test_msg";
// this send works correctly
sendto(skt, (char*)txBuf, sizeof(txBuf), 0, (sockaddr*)&toAddr, sizeof(toAddr));
sockaddr_in rxAddr;
int fromAddrLen = sizeof(rxAddr);
uint8_t rxBuf[1000];
// this receive also works
recvfrom(skt, (char*)rxBuf, sizeof(rxBuf), 0, (sockaddr*)&rxAddr, fromAddrLen);
uint16_t nextPort = *((uint16_t*)rxBuf+0);
toAddr.sin_port = htons(nextPort);
// this send triggers the server log that the client IP/port is unknown
sendto(skt, (char*)txBuf, sizeof(txBuf), 0, (sockaddr*)&toAddr, sizeof(toAddr));

My question is, in the code above, is the 2nd send guaranteed to come from the same IP/port combination as the first send?我的问题是,在上面的代码中,第二次发送是否保证来自与第一次发送相同的 IP/端口组合? And if not, how can I change the above code to gaurantee it without binding (I don't know the client IP to bind to and don't know what ports are available)?如果没有,我怎样才能更改上面的代码以保证它没有绑定(我不知道要绑定的客户端 IP 并且不知道哪些端口可用)?

EDIT: I learned the hard way previously about how NATs prevent servers from making first contact (which is why the client sends to thread1, gets response, then sends to thread2 instead of thread1 directly telling thread2 to respond).编辑:我以前学到了关于 NAT 如何阻止服务器进行第一次联系的艰难方法(这就是为什么客户端发送到 thread1,获得响应,然后发送到 thread2 而不是 thread1 直接告诉 thread2 响应的原因)。 Remembering this fun time, I'm starting to wonder if the behavior I'm seeing is due to NAT behavior that's different in some cases from all of the NATs my test assets have.想起这段有趣的时光,我开始怀疑我看到的行为是否是由于 NAT 行为导致的,在某些情况下,这与我的测试资产所具有的所有 NAT 不同。 I know NATs create a linkage between the client's IP and server's IP and that the server sees the NAT generated client IP/port instead of the IP/port that the client sees.我知道 NAT 在客户端的 IP 和服务器的 IP 之间创建了一个链接,并且服务器看到的是 NAT 生成的客户端 IP/端口,而不是客户端看到的 IP/端口。 I was thinking that the NAT used the same linkage when the client started sending to the new server port (same server IP).我在想当客户端开始发送到新的服务器端口(相同的服务器 IP)时,NAT 使用了相同的链接。 Was that wrong?那是错的吗? Does the fact that the client starts sending to a different port potentially cause a different NAT IP/port that the server ultimately sees?客户端开始发送到不同端口的事实是否可能导致服务器最终看到的不同 NAT IP/端口?

I believe your error is that you are using UDP and this protocol does not have error correction.我相信您的错误是您使用的是 UDP 并且该协议没有纠错功能。 There is no guarantee that the packet will be received, or that packets will be received in order, or that packets will be received only once.不保证数据包会被接收,或者数据包会按顺序接收,或者数据包只会被接收一次。

You appear to be doing some kind of transaction that depends on the order packets are received.您似乎正在执行某种取决于收到的订单数据包的交易。 Testing locally is likely to always work, but as soon as you are on a wider area network you fill find dropped and out of order packets.本地测试可能总是有效的,但是一旦您进入更广的区域网络,您就会发现丢失和无序的数据包。

You can solve this by either using TCP, or by designing your own solution in UDP.您可以通过使用 TCP 或在 UDP 中设计自己的解决方案来解决此问题。 Generally, unless you have specific performance reasons not to, you should use TCP.通常,除非您有特定的性能原因不这样做,否则您应该使用 TCP。

The answer turns out to be that the client IP/port is not guaranteed to stay the same.答案是不能保证客户端 IP/端口保持不变。 I added debug to the server and saw it happen again, so was able to verify that when the client changed it's send-to port, it caused the server to see a different client send-from port.我向服务器添加了调试并看到它再次发生,因此能够验证当客户端更改它的发送端口时,它会导致服务器看到不同的客户端发送端口。

I'm not entirely sure if this is due to something in the OS being different for some clients or if it was because of different NAT behavior.我不完全确定这是由于某些客户端的操作系统中的某些内容不同,还是由于 NAT 行为不同。 For my purposes, it doesn't matter -- I had to change code to work with it either way.就我的目的而言,这并不重要——无论哪种方式,我都必须更改代码才能使用它。 If anybody can definitively say (and hopefully point to documentation) that it was the OS and/or NAT, please do and I'll change the accepted answer to it如果有人可以明确地说(并希望指向文档)它是操作系统和/或 NAT,请这样做,我会更改接受的答案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM