Click here to Skip to main content
15,881,089 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
I'm using UdpClient to send a message and listen for a response, like this:

Client = gcnew UdpClient();
HostEndPoint = gcnew IPEndPoint(192.168.0.20, 52381);
Client->Connect(HostEndPoint);
Client->Send(Message, Message->Length);
Bytes = Client->Receieve(HostEndPoint);


I have two similar devices but they respond differently. In the first case, the destination responds on the same port as I send to. So, for example, sending with a random source port of 49542, this happens:

 Request: 192.168.1.10:49542 > 192.168.1.20:52381
Response: 192.168.1.20:52381 > 192.168.1.10:49542


And with the above code I get the response as expected.

The other device however responds with a random port (which changes whenever it is powercycled), like this:

 Request: 192.168.1.10:49542 > 192.168.1.20:52381
Response: 192.168.1.20:46468 > 192.168.1.10:49542


And in this case, I do not receive the response, Receieve() will timeout.

I have monitored the communication with WireShark and I can see the messages in both directions. So I know the device is responding I just can't figure out how to receive it in my code.

The best solution I think is to be able to receive any response that arrives to my source random port (49542 above), additionally to specify the destination IP as well, but that may not be needed. Alternatively, to listen for any response from the destination IP, on any port, since I don't see how to know what port the device is responding with.

What I have tried:

I've tried all sorts ot things I found online, but nothing specifically discusses the random response port issue.

This is the first time I've encountered this and it seems weird to me. The devices are from a major manufacturer though, that surely knows what they're doing.
Posted
Updated 23-May-21 18:24pm

I believe I have solved this. The trick is to not use Connect, but instead to pass HostEndPoint in the Send command. This approach works with both devices.

Client = gcnew UdpClient();
HostEndPoint = gcnew IPEndPoint(192.168.0.20, 52381);
// Client->Connect(HostEndPoint);
Client->Send(Message, Message->Length, HostEndPoint);
Bytes = Client->Receieve(HostEndPoint);


Although it's working, I'm not completely sure what messages it will allow thru. It might allow any port from the specified IP, or it might allow any response from the specified IP that is directed to the initial random source port. I'm not sure.

Also, I initially thought I might have to set HostEndPoint->Port = 0 between Send and Receive. That works, but it isn't necessary.
 
Share this answer
 
Comments
Richard MacCutchan 24-May-21 4:10am    
Since UDP is a connectionless protocol, you cannot expect the messages to behave in the same way as TCP messages.
Greg Utas 24-May-21 8:26am    
Glad you fixed it. Connect and Send (if C# uses standard names here) are primarily for TCP, not UDP. UDP doesn't really have an equivalent to connect() and typically uses sendto() and recvfrom() instead of send() and recv().
Member 2744674 24-May-21 10:41am    
UdpClient has a Connect() function which seems to cause the Receive function to be filtered.
I have never seen a device do that but what ever. According to a similar Q&A at stackoverflow, the answer is to use recvfrom or something equivalent in the library you are using. Here it is : c - Server/client UDP, sender uses a random port - Stack Overflow[^]

BTW - the search terms I used to find that were "UDP response random port number", not quoted.
 
Share this answer
 
v2
Comments
Member 2744674 23-May-21 22:33pm    
This isn't applicable to my post. What you linked to is primarily talking about the server end. I'm doing the client end, communicating with a server device. I've googled similarily already.
Rick York 24-May-21 11:21am    
Yes, it is applicable. You are trying to receive a response and you don't know the port number - that's how to do it.
When you receive a message, try to match on both the client's IP address and port number. If that fails, try to match on just the IP address. This would be a problem if a given IP address could have more than one client active, but it doesn't sound like you need to handle that. It's curious, though, that this device can remember your port number after cycling power, but not the one it was sending on!
 
Share this answer
 
Comments
Member 2744674 23-May-21 18:19pm    
The problem is that no message is received via HostEndPoint as shown in the sample code, with the second device.

I'm not sure what you're thinking is with regard to power cycling. When the device power cycles, it chooses a new random response port (46468 above) and uses that in all reponses to any of this particular inquiry. The device doesn't know what port to send its response to until it recieves an inquiry. It does respond to the correct source port (my client's random porT), but it changes the (destination) port to its randomly selected port. And this is where the problem is as Receieve(HostEndPoint) is listening on the wrong port, and can't know what port to listen to with a gcnew IPEndPoint(192.168.0.20, ???).
Greg Utas 23-May-21 18:35pm    
Maybe I misunderstand. You send to 192.168.1.20:52381 from port 49542 but the reply is from 192.168.1.20:46468. The reply still goes to your port 49542, however, and the reply still comes from 192.168.1.20, albeit from a different port. So if I've got this right, use the 192.168.1.20 as a fallback way of finding the session after the lookup using port 52381 fails.
Member 2744674 23-May-21 18:48pm    
Yes, that's what's happening.

As best as I can figure out you have to indicate a port # for Receive(IPEndPoint), which usually is the destination port of the message you sent to in the first place - as it is in my code sample (which works with the first device). The random port chosen by Connect can't be listened to, that's the receiving port, but I think Recieve listens for the sending port from the device. There's also some suggestion in .net docs that once you use a IPEndPoint with UdpClient() or Connect(), any other responses are filtered out. So, I'm not even sure why Receive has an IPEndPoint parameter.

I tend to think that the fact that I can't find any information about how this can be done suggests that it can't be done because devices aren't supposed to respond from a random port. But, I've discussed this issue with the manufacturer and they insist it's correct behavior.

Also note, I've tried to create a second UdpClient to listen for the response from the destination IP, but it also requires a port be defined, and there's no way I can tell to know what port to listen for. I have tried UdpClient()->Client->RemoteEndPoint, but I'm pretty sure, this is the endpoint I'm starting with which has the known port, not the random port.
Greg Utas 23-May-21 19:39pm    
I'm not familiar with the C# interfaces for this. But you're using UDP, where the usual procedure is for all clients to send to your well-known port (49542) and for you to accept *all* messages received on that port. It's a lot like a listener port in TCP, but both ends just keep using the same port instead of you moving it to a dedicated port with accept().

So look at C#'s UDP interface to see how you can receive all messages on your port, regardless of who sent them. When you receive a message--the function that does this is normally called recvfrom()--you'll be told the sender's IP address and port. You can then do what I suggested. If no session is associated with the sender's IP address, the message is stale (or misdirected, or worse), so just discard it.
Member 2744674 23-May-21 22:28pm    
I'm coding the client end, not the server end. You've got it backwards. This isn't what my post is about.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900