views:

65

answers:

2

The "connectionless" aspect of UDP has thrown me for a loop...

If I setup a UDP socket set to INADDR_ANY, then bind that to port 33445 on the local machine, the machine will accept incoming connections from various clients. All of these connections will be serviced by that one socket, since this is not TCP and I cannot spawning a new child sockets to handle each connection directly. I am able to reply to any, some, or all of these connected clients, from their latest message.

So where things get a little fuzzy for me is here...

Am I able to also send out messages at any time to any of these clients? or can I only send messages that in response of recvfrom() ?

Separately, if I wanted that server (while it is serving clients) to connect to another server and have a conversation about something else, I assume I will need to create a new socket for this purpose? I cannot just use the existing server socket and specify a new destination address?

Many thanks to this wonderful community.

Edit: Let me put it another way.. It seems to be that I can only use the bound socket for responding to clients that have previously reached me on that socket. To initiate a conversation with a new host, I cannot simply use the bound socket for that purpose? I must create a new socket in order to reach a server that is listening, correct?

+1  A: 

UDP sockets aren't connected to a remote host or client, so all you need to do is to use sendto() using the destination address and the UDP socket you have initialized. So yes, you can send out messages using the UDP socket at any time given that you have set up the UDP socket correctly. Just set the receiving address in the sockaddr struct you are using. If the receiving part have a UDP socket bound on the port you are sending the message, then it will receive it.

On that 2nd question it all depends if the conversation with that 2nd server uses a different port. If it uses the same port then there is no need to create another UDP socket. You just have to separate the messages the server 1 gets from its clients from messages it gets from server 2 somehow.

Ill recommend taking a look at Beej's excellent guide chapter 5.8 and 6.3.

Beej's Guide to Network Programming

ETroll
+3  A: 

UDP sockets can operate in two different modes:

  • default not-connected mode: all datagrams sent to the port/address of your process are received; you need to specify destination address for each send you do.
  • connected mode: only the datagrams sent from the address/port you connected to are received; you don't need to specify destination address on each send.

Here's a small review of connected UDP sockets.

Edit:

Here's a little python UDP server that accepts packets from any client and copies them to a second server. Everything is done with one not-connected UDP socket.

#!/usr/bin/env python
import sys, socket, string

if len( sys.argv ) != 4:
        print "Usage: udptee <local-listen-port> <copy-host> <copy-port>"
        exit( 1 )

copy = ( sys.argv[2], int( sys.argv[3] ))

s = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
#s.bind(( 'localhost', int( sys.argv[1] )))
s.bind(( '', int( sys.argv[1] )))

print "listening on ", s.getsockname()
print "copying to", copy

while True:
        line, addr = s.recvfrom( 1024 )
        print "received: ", line, " from ", addr
        s.sendto( line, addr ) # echo to source
        s.sendto( line, copy ) # copy to tee
        if string.strip( line ) == "exit": break

print "Goodbye and thanks for all the fish"
s.close()

Run it in one terminal as:

~$ ./udptee 9090 <IP-of-copy-server> 9999

Then start netcat in server mode in second term. This one will accept copies of the datagrams:

# this used to be "nc -ul 127.0.0.1 9999" which only listened on loopback
~$ nc -ul 9999

Start netcat client in third term to send stuff to the first server:

~$ nc -u <IP-of-tee-server> 9090

Start typing and see both servers echo what you type.

Nikolai N Fetissov
in non-connected mode, am I limited to sending only to clients that have connected? will the socket accept a sendto() call on an address that has not connected to me (i.e. a new connection)?
bitcruncher
With UDP, "connected" is a property of one end, i.e. one side in UDP conversation can be "connected" and send/receive to/from one address/port, while the other side might be not-connected and talk to many other destinations. So unless you call `connect(2)` on your socket, it's free to receive/send to anybody. Hope this makes it clear.
Nikolai N Fetissov
If that's the case, then for some reason my system is not letting me sendto() an arbitrary listener, but it *is* letting me respond to a client that has reached me.
bitcruncher
How do you know it's "not letting you"? Do you get an error, or the packet is lost?
Nikolai N Fetissov
sendto() fails with -1 : Invalid argument. i've checked and played with the address struct several times, but no dice.
bitcruncher
Can you paste that code into the question. That's suspicious.
Nikolai N Fetissov
I can do one better. I paused my binary development and took to testing this particular concept on PHP. To my surprise, it also failed in the same manner: -1 : invalid arg. So, I knew I had to be violating some cardinal socket rule. I rewrote the test code to use two sockets (one incoming, one outgoing) and, as desired, the incoming socket received and responded to ONLY connected clients. The outgoing socket was able to direct the other communication as desired. have a look:http://cl1p.net/upd_failcode/vs. http://cl1p.net/udp_successcode/
bitcruncher
In your failing example you are giving `sendto` a string for the port, while it's integer in succeeding one. I'm not an ace in php, but it looks like *the* problem. I'm pasting a little sample into the answer to prove the point.
Nikolai N Fetissov
could have been a copy/paste issue since I didn't exactly save the code that failed. but just for laughs, i changed the port to a native int on the failcode and it's no different. i'll check out your python example.
bitcruncher
ok. so i've reviewed your code, but I think something is still missing. my fail code also works in this manner, but i think if you moved your copy server to somewhere other than the localhost, you will have problems. if i use 127.0.0.1 on the failcode, it actually doesn't fail, much like your script here. now, specify the copy server to be an external machine, and this fails. here was my result of your code: http://cl1p.net/network_unavailable/
bitcruncher
OK, couple of modifications - empty string instead of 'localhost' in python script to bind to ALL addresses, no IP on `nc` server line to do the same.
Nikolai N Fetissov
this is most interesting. so, if we bind to nothing, then the socket is basically free to roam and respond to whatever comes its way and whichever way the socket is directed. i think you proved your point well. +1
bitcruncher