?
Solved

UDP Server with Multiple Clients -- Simultaneously

Posted on 2003-02-28
13
Medium Priority
?
393 Views
Last Modified: 2013-11-13
I have a UDP Server (not TCP) that can work with multiple clients using Winsock control (the clients are on the same machine but different port numbers or may be on different machines). However, the Server does not work with the clients simultaneously. It seems to only communicate properly with the first client. I want the control to respond to each client's request, but it does not seem to be doing that.

Make three projects and executables: Server, Client1 and Client2.

For Server. Add textbox "txtSend", textbox "txtReceived", commandbutton "cmdSend" and winsock "sckServer" to the form. Set "sckServer" Protocol to sckUDPProtocol. Use this code in the form:

---
Option Explicit

Private Sub cmdSend_Click()
   sckServer.SendData txtSend.Text
End Sub

Private Sub Form_Load()
   With sckServer
       .RemoteHost = "localhost"
       .RemotePort = 1002
       .Bind 1001
   End With
End Sub

Private Sub sckServer_DataArrival(ByVal bytesTotal As Long)
   Dim strData As String
   
   sckServer.GetData strData
   txtReceived.Text = txtReceived.Text & strData & vbCrLf
End Sub
---

For Client1. Add textbox "txtSend", textbox "txtReceived", commandbutton "cmdSend" and winsock "sckClient" to the form. Set "sckClient" Protocol to sckUDPProtocol. Use this code in the form:

---
Option Explicit

Private Sub cmdSend_Click()
   sckClient.SendData txtSend.Text
End Sub

Private Sub Form_Load()
   With sckClient
       .RemoteHost = "localhost"
       .RemotePort = 1001
       .Bind 1002
   End With
End Sub

Private Sub sckClient_DataArrival(ByVal bytesTotal As Long)
   Dim strData As String
   
   sckClient.GetData strData
   txtReceived.Text = txtReceived.Text & strData & vbCrLf
End Sub
---

For Client2. Add textbox "txtSend", textbox "txtReceived", commandbutton "cmdSend" and winsock "sckClient" to the form. Set "sckClient" Protocol to sckUDPProtocol. Use this code in the form (note the change for the port number, from 1002 to 1003):

---
Option Explicit

Private Sub cmdSend_Click()
   sckClient.SendData txtSend.Text
End Sub

Private Sub Form_Load()
   With sckClient
       .RemoteHost = "localhost"
       .RemotePort = 1001
       .Bind 1003
   End With
End Sub

Private Sub sckClient_DataArrival(ByVal bytesTotal As Long)
   Dim strData As String
   
   sckClient.GetData strData
   txtReceived.Text = txtReceived.Text & strData & vbCrLf
End Sub
---

Compile all of those to executables (Server, Client1, Client2).

+ start Server
+ start Client1
+ start Client2
+ from Client1, type "Client1" and select "Send"
+ on Server, verify that you see the message
+ from Server, type "Server" and select "Send"
+ on Client1, verify that you see the message
+ on Client2, verify that you do NOT see the message
+ from Client2, type "Client2" and select "Send"
+ on Server, verify that you see the message
+ from Server, type "Server" and select "Send"
+ on Client2, verify that you do NOT see the message
+ on Client1, verify that you see the message

The last two are not what I want (I want the reverse).
0
Comment
Question by:GivenRandy
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
13 Comments
 
LVL 28

Accepted Solution

by:
AzraSound earned 2000 total points
ID: 8044840
Hey Randy, how's it going?

Well, I'm not going to pretend that I know a whole lot about socket programming, but here is what I gathered from your question...


Your RemotePort value specified by the server was static, that is, you set it initially and it never changed.  So I thought, simple fix...just change the RemotePort property to the value of the port from the client who made the latest request and voila!  Well, problem #1 is, you don't know who sent the request, so to overcome that, I would guess you need to pass the client port as part of its data message to the server.

Before posting that solution, however, I tried it out, and you know what?  It didn't work!  I set the RemotePort value just prior to the server sending out the data back to the client, but it still went to the first client that made a request from the server.  So, if Client1 was the first to send data to the server, the server always only talked to him.  If Client2 was the first to send data to the server, the server always only talked to him.

I don't know enough about UDP as to why that might be.  I understand it is a connection-less protocol, but it still seems it should recognize I want to send data to a different port (that I specify).  At any rate, I only fooled with it for a few minutes, and all I could come up with was "resetting" the server each time a request was made.  This means closing the "connection" (which shouldn't exist, in theory, in a connection-less protocol) and reopening it, pointing to the port of the client who submitted the most recent request.  It seems sloppy, and it seems to go against the logic of how I feel it should work, but here it is:



--------
SERVER
--------

Option Explicit

Private m_lngCurrentClientPort      As Long


Private Sub cmdSend_Click()
  With sckServer
    .Close
 
    .RemoteHost = "localhost"
    .RemotePort = m_lngCurrentClientPort
    .Bind 1001
    .SendData txtSend.Text
  End With
End Sub

Private Sub Form_Load()
  With sckServer
      .RemoteHost = "localhost"
      .RemotePort = 1003
      .Bind 1001
  End With
End Sub

Private Sub sckServer_DataArrival(ByVal bytesTotal As Long)
  Dim strData As String
 
  sckServer.GetData strData
  m_lngCurrentClientPort = Split(strData, "::")(0)
 
  txtReceived.Text = txtReceived.Text & Split(strData, "::")(1) & vbCrLf
End Sub




--------
CLIENT1
--------

Option Explicit


Private Sub cmdSend_Click()
  sckClient.SendData sckClient.LocalPort & "::" & txtSend.Text
End Sub

Private Sub Form_Load()
  With sckClient
      .RemoteHost = "localhost"
      .RemotePort = 1001
      .Bind 1002
  End With
End Sub

Private Sub sckClient_DataArrival(ByVal bytesTotal As Long)
  Dim strData As String
 
  sckClient.GetData strData
  txtReceived.Text = txtReceived.Text & strData & vbCrLf
End Sub




--------
CLIENT2
--------

Option Explicit


Private Sub cmdSend_Click()
  sckClient.SendData sckClient.LocalPort & "::" & txtSend.Text
End Sub

Private Sub Form_Load()
  With sckClient
      .RemoteHost = "localhost"
      .RemotePort = 1001
      .Bind 1003
  End With
End Sub



Private Sub sckClient_DataArrival(ByVal bytesTotal As Long)
  Dim strData As String

  sckClient.GetData strData
  txtReceived.Text = txtReceived.Text & strData & vbCrLf
End Sub
0
 
LVL 27

Expert Comment

by:Dabas
ID: 8045038
Dear Randy:

I have a UDP client/server solution and it is working, (5 clients all over Australia!).
I know what you are talking about, and have had similar problems.

Most of my problems got solved by not relying at all on the .RemoteHost property, rather the .RemoteHostIP property.

I also use a control array of winsocks controls. Each control has its own RemoteHostIP, RemotePort and Bind.
At the client end the winsock connects to a different port on the server, based on the value of an .ini file.

Hope this helps!
0
 
LVL 17

Expert Comment

by:inthedark
ID: 8046113
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 9

Author Comment

by:GivenRandy
ID: 8057691
AzraSound, that may be the only approach. It would appear that the Winsock control is flawed.

When I get the DataArrival event in the Server, it DOES recognize the proper remote port and IP address (the latter does not change, since all of them are on the same machine). However, when it sends out a response, it does not send it to the correct port, even when the RemotePort shows that it is correct. For example, upon DataArrival it switches from 1002 to 1003 and stays at 1003 just before SendData, but the SendData actually ends up going to 1002.

By the way, I looked at my reference W. Richard Stevens books ("UNIX Network Programming" and "Advanced Programming in the UNIX Environment") and Bob Quinn's book ("Windows Sockets Network Programming") and they basically confirmed what we thought. Most of their (and my) focus has been on TCP instead of UDP). I will also post as a possible problem on Microsoft.
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 8057735
It sure does seem like a possible problem.  Debugging definitely shows that the server "knows" which port he should be sending data to, but, in the end, he only sends to the client who first initiated contact with him.  If I remember correctly, I tried it where the server defaulted to a RemotePort of 1002, but if a message from 1003 came first, the server successfully switched from 1002 to 1003 and sent the message back accordingly.  Once that initial connection is made, it seems the server never wants to let go.  A pretty stubborn connection-less protocol implementation wouldn't you say?   ;-)
0
 
LVL 9

Author Comment

by:GivenRandy
ID: 8057756
AzraSound, that may be the only approach. It would appear that the Winsock control is flawed.

When I get the DataArrival event in the Server, it DOES recognize the proper remote port and IP address (the latter does not change, since all of them are on the same machine). However, when it sends out a response, it does not send it to the correct port, even when the RemotePort shows that it is correct. For example, upon DataArrival it switches from 1002 to 1003 and stays at 1003 just before SendData, but the SendData actually ends up going to 1002.

By the way, I looked at my reference W. Richard Stevens books ("UNIX Network Programming" and "Advanced Programming in the UNIX Environment") and Bob Quinn's book ("Windows Sockets Network Programming") and they basically confirmed what we thought. Most of their (and my) focus has been on TCP instead of UDP). I will also post as a possible problem on Microsoft.
0
 
LVL 9

Author Comment

by:GivenRandy
ID: 8057761
... oops ... hit wrong button and sent double response.
0
 
LVL 9

Author Comment

by:GivenRandy
ID: 8057771
That works for now and does not cause large time problems (it does impact throughput, but works). Thanks!
0
 
LVL 9

Author Comment

by:GivenRandy
ID: 8057795
Like this:

---
Private Sub cmdSend_Click()
    Dim lngTempPort As Long
   
    With sckServer
        lngTempPort = .RemotePort
        .Close
        .RemoteHost = "localhost"
        .RemotePort = lngTempPort
        .Bind 1001
        .SendData txtSend.Text
    End With
End Sub
---
0
 
LVL 9

Author Comment

by:GivenRandy
ID: 8057838
By the way, this KnowledgeBase article was updated a couple months ago, but it does not work:

http://support.microsoft.com/default.aspx?scid=kb;en-us;192564
0
 
LVL 9

Author Comment

by:GivenRandy
ID: 8057901
p.s., of course you have to set both RemotePort and RemoteHostIP and should pass that information along with the packets. Still, it should not be necessary to actually close the socket each time.
0
 
LVL 28

Expert Comment

by:AzraSound
ID: 8058073
Glad I could help  :-)

If you hear anything from MS about this issue, do update us.  It would be interesting to hear what they have to say.
0
 
LVL 3

Expert Comment

by:Ficus
ID: 8417559
I came across this...

From Microsoft Knowledge Base Article - 192564
----------------------------------------------------
This article was previously published under Q192564

SUMMARY
When a UDP message is received by a Winsock control, the RemoteHostIP property is set to the IP address of the remote machine, and the RemotePort property is set to the IP port of the remote UDP application. The previous properties values are overwritten.

This could create a problem if the user was not expecting data on that port from a different RemoteHostIP. Attempts to call the SendData method without setting these two properties to the appropriate values might send the data to an unplanned recipient.

Whenever a UDP socket is being used, you should always reset the RemoteHostIP and RemotePort properties to your own known values before calling the SendData method.
MORE INFORMATION

This is by design. At the Winsock layer, the sendto API requires a sockaddr structure of the remote UDP peer to send the message to, and the recvfrom API always gets a sockaddr structure for the remote UDP peer. The Winsock control internally uses the same sockaddr structure in both sendto and recvfrom API. As UDP is a connectionless protocol, it is possible that one UDP peer could receive a UDP message from a third machine unexpectedly. Therefore, it is important to reset the RemoteHostIP and RemotePort properties to your own known values before calling the SendData method.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

How to remove superseded packages in windows w60 or w61 installation media (.wim) or online system to prevent unnecessary space. w60 means Windows Vista or Windows Server 2008. w61 means Windows 7 or Windows Server 2008 R2. There are various …
Having just graduated from college and entered the workforce, I don’t find myself always using the tools and programs I grew accustomed to over the past four years. However, there is one program I continually find myself reverting back to…R.   So …
The viewer will learn how to implement Singleton Design Pattern in Java.
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
Suggested Courses

765 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question