Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Languages / C# / March 2008

Tip: Looking for answers? Try searching our database.

Unicast UDP Server

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
O.B. - 28 Mar 2008 03:07 GMT
I'm attempting to set up at UDP server in unicast mode, where
10.1.16.25 is the remote machine.  Below is the error being thrown
when binding the socket.  What am I doing wrong?

System.Net.Sockets.SocketException
"The requested address is not valid in its context"

Socket socket = new Socket(AddressFamily.InterNetwork,
                          SocketType.Dgram,
                          ProtocolType.Udp);

socket.SetSocketOption(
   SocketOptionLevel.Socket,
   SocketOptionName.ReceiveBuffer,
   75000000);  // 75 MB

socket.SetSocketOption(
   SocketOptionLevel.Socket,
   SocketOptionName.SendBuffer,
   1472);

EndPoint receiveEndPoint = new IPEndPoint(
   System.Net.IPAddress.Parse("10.1.16.25"),
   socketConfig.Port);

socket.Bind(receiveEndPoint);
Peter Duniho - 28 Mar 2008 04:07 GMT
> I'm attempting to set up at UDP server in unicast mode, where
> 10.1.16.25 is the remote machine.  Below is the error being thrown
> when binding the socket.  What am I doing wrong?

You're trying to bind your local socket to a remote address.

If you want to specify a remote address to be used as the default  
destination for the UDP socket, use Connect(), not Bind().

By the way...IMHO, you shouldn't be messing with the socket buffer sizes  
unless you have already gotten everything else working, you know exactly  
what you're doing, _and_ you have run into some problem that requires you  
to change the default buffer sizes.

Pete
O.B. - 28 Mar 2008 15:40 GMT
On Mar 27, 10:07 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> > I'm attempting to set up at UDP server in unicast mode, where
> > 10.1.16.25 is the remote machine.  Below is the error being thrown
[quoted text clipped - 4 lines]
> If you want to specify a remote address to be used as the default
> destination for the UDP socket, use Connect(), not Bind().

But that would require the remote connection to be Bound to that port
to accept connections.  Here is the dilemma.  We have a user that has
other commercial software that is only capable of running their
sockets as client UDP broadcast connections on a fixed port.  On our
end, the user wants the ability to open two UDP servers both on the
same port, but for each one to filter based on the IP that is sending
data.  I was hoping that it would be possible to do this in the
connection setup rather than having our asynchronous receive callback
do the filtering.

With that said, what is the point of binding to a specific address if
it isn't allowed?

> By the way...IMHO, you shouldn't be messing with the socket buffer sizes
> unless you have already gotten everything else working, you know exactly
> what you're doing, _and_ you have run into some problem that requires you
> to change the default buffer sizes.

We started off with defaults and lost too many packets.  75 MB ended
up being a good number.  Most of our machines are running with 4 GB or
more of memory, so it isn't an issue.
Peter Duniho - 28 Mar 2008 18:49 GMT
>> If you want to specify a remote address to be used as the default
>> destination for the UDP socket, use Connect(), not Bind().
>
> But that would require the remote connection to be Bound to that port
> to accept connections.

For you to send directly to a remote socket, it has to be bound to a known  
port, yes.  Likewise, for you to send a broadcast to a remote socket, it  
has to be bound to a known port.  And either case, you'd send your  
datagram to that known port.  You can either use Connect() to specify the  
remote address (including the broadcast IP address and the target port),  
or you can explicitly provide the address each time you send.

But Bind() has nothing to do with any of that.

> Here is the dilemma.  We have a user that has
> other commercial software that is only capable of running their
> sockets as client UDP broadcast connections on a fixed port.

There's no such thing as a "UDP connection".  I'll just ignore the word  
"connection" there.

As far as receiving broadcasts goes...if your clients are for some reason  
required to listen for broadcasts only on a specific port, then you'll  
have to broadcast on that port.

I don't really understand your statement that the software "that is only  
capable of running their sockets as client UDP broadcast".  If a socket  
can receive a broadcast, it can also receive a datagram sent directly to  
it.  So the stipulation that broadcasts must be involved seems odd to me.

Finally, I'm assuming this is all on the same network segment or segments  
connected such that the broadcasts are routed properly to the recipient.

> On our
> end, the user wants the ability to open two UDP servers both on the
> same port, but for each one to filter based on the IP that is sending
> data.  I was hoping that it would be possible to do this in the
> connection setup rather than having our asynchronous receive callback
> do the filtering.

Again: with UDP there's no such thing as a connection.  That said, you  
_can_ use the Connect() method to specify a remote address from which  
datagrams may be received, discarding datagrams sent by any other  
address.  It doesn't create a connection, but it does do what you seem to  
want it to do.

Keeping in mind, however, that you cannot have two UDP sockets bound to  
the same local address.  If you've got two different computers, or at  
least two different adapters on the same computer, this should be fine.  
But if you've got a single network adapter on a single computer, you can't  
reliably have two UDP servers bound to the same port (you can use the  
"reuse address" option, but when you do that, the OS provides no  
guarantess as to which socket will receive which datagram).

> With that said, what is the point of binding to a specific address if
> it isn't allowed?

If it weren't allowed, you're right...there wouldn't be any point in  
binding.  But it is allowed.  It just does something different than what  
you seem to think it does.

Bind() specifies the _local_ endpoint for the socket.  It essentially  
labels the socket you're operating with, so that other sockets can  
communicate with it.  If you specify an IP address, it must be a valid IP  
address for the local host.  You may specify IPAddress.Any for the  
address, in which case the OS will choose an adapter (for client sockets)  
or listen on all adapters (for server sockets).

Connect(), on the other hand, specifies the _remote_ endpoint for the  
socket.  If you specify an IP address, it must be a valid IP address for  
the _other_ end of your communications.  This could in fact be your local  
host's IP address, but _only_ if you are communicating with another socket  
on the same network adapter/computer.  In any case, it doesn't label  
anything...it simply sets up the link between the socket you're operating  
with and some remote socket.  For a TCP socket an actual connection is  
created, but for a UDP socket all it does is set some internal state for  
the local socket that the OS then uses when you call Send() and Receive().

>> By the way...IMHO, you shouldn't be messing with the socket buffer sizes
>> unless you have already gotten everything else working, you know exactly
[quoted text clipped - 5 lines]
> up being a good number.  Most of our machines are running with 4 GB or
> more of memory, so it isn't an issue.

Okay.  If you're running all of this on a LAN, over a gigabit network, in  
an extremely high-volume situation, that _might_ be reasonable.  
Otherwise, that's an awful lot of data to pile up without your servers  
being able to process it.  If one or more of those descriptions don't  
apply to your situation, you could (and should IMHO) probably fix the  
issue in a more appropriate way (i.e. just fixing the code so that it's  
more responsive).

Pete
O.B. - 29 Mar 2008 23:18 GMT
Wow, this is great.  All this time I have been confusing bind and
connect.  Thank you for the detailed explanation.

For the record, I still have to bind to a _local_ IP address for UDP
sockets in order for the receive data callback to be invoked.  From what
I gathered from your post, invoking "connect" with a remote address in a
UDP socket will ensure that the receive callback is only invoked with
data received from the specified remote address, correct?

Continued below.

>>> By the way...IMHO, you shouldn't be messing with the socket buffer sizes
>>> unless you have already gotten everything else working, you know exactly
[quoted text clipped - 12 lines]
> issue in a more appropriate way (i.e. just fixing the code so that it's
> more responsive).

The code has been rewritten using unmanaged code to get a significant
speed up over the original C++ implementation.  Without the 75 MB
receive buffer, we _occasionally_ find the buffer overfilling.

In running a profiler, it appears the code is processing the data as
fast as the OS is invoking the asynchronous callback.  As a test, I
wrote a receive callback that only sucked data off the socket and put it
into an internal buffer for processing.  We were still encountering an
overflow ... very odd.  Maybe it is the actual NIC we're using?  Or is
it a limitation of Windows XP and Windows 2003 Server?  This is a tough
one to figure out.
Peter Duniho - 29 Mar 2008 23:58 GMT
> Wow, this is great.  All this time I have been confusing bind and  
> connect.  Thank you for the detailed explanation.

You're welcome.

> For the record, I still have to bind to a _local_ IP address for UDP  
> sockets in order for the receive data callback to be invoked.  From what  
> I gathered from your post, invoking "connect" with a remote address in a  
> UDP socket will ensure that the receive callback is only invoked with  
> data received from the specified remote address, correct?

It should, yes.

> [...]
> The code has been rewritten using unmanaged code to get a significant  
> speed up over the original C++ implementation.  Without the 75 MB  
> receive buffer, we _occasionally_ find the buffer overfilling.

I don't understand the above comment.  If you're using unmanaged code, why  
are you posting in the C# newsgroup?  C# is dependent on the .NET runtime,  
and so is inherently tied to managed code.  If the original implementation  
was C++, is the above statement meant to imply that you were using managed  
C++?

> In running a profiler, it appears the code is processing the data as  
> fast as the OS is invoking the asynchronous callback.  As a test, I  
> wrote a receive callback that only sucked data off the socket and put it  
> into an internal buffer for processing.  We were still encountering an  
> overflow ... very odd.

How do you know you are encountering an overflow?  Are you sure that you  
aren't losing datagrams due to some other reason?

> Maybe it is the actual NIC we're using?  Or is it a limitation of  
> Windows XP and Windows 2003 Server?  This is a tough one to figure out.

The "U" in "UDP" might as well stand for "unreliable".  UDP is inherently  
unreliable, and you _will_ lose datagrams eventually, no matter what you  
do.

On a LAN, you can avoid many of the problems that exist going over the  
Internet, but your code still must always be able to deal with lost  
datagrams.  Data loss will be reduced significantly on a LAN as compared  
to the Internet, but it will never go away completely.

You haven't made any mention as to what your actual network speed and load  
is, but I'll reiterate my previous statement: only on the fastest  
networks, under the highest loads, should a buffer of 75MB be useful.  
Even at that size, that's on the order of 500 ms worth of constant data  
throughput on a 1 gigabit network.  Or put another way, if a 75MB buffer  
is needed, that means that the layer of network transport that's supposed  
to be reading from that buffer is at times being delayed by longer than  
500 ms.

On a modern computer, that's practically forever.  In my opinion, you  
should never be seeing delays that long.  If you are seeing delays that  
long, there's probably a better way to deal with them.  Such as,  
preventing the delays rather than allowing them to happen and just letting  
the data pile up in a larger buffer.

As an example of that 500 ms really means: you'd have to be running  
roughly ten fully CPU-bound threads on a single-core/CPU computer in order  
for some other thread's execution to be delayed by that much time.  And of  
course, running ten fully CPU-bound threads on a single-core computer is  
definitely not a good idea (heck, running just two fully CPU-bound threads  
on a single-core computer isn't a good idea).

If you're running on a more conventional network (e.g. 100 Mb/s...though I  
admit, 1 Gb/s is getting more and more common, I think 100 Mb/s is still  
more typical), and/or your data transmission rate does not saturate the  
network, then a 75MB buffer implies an even larger delay (for a 100 Mb/s,  
it's more like 5 seconds than 500 ms).  And if a half-second delay is a  
sign of something wrong, you can imagine that an even larger delay means.  
:)

Pete
O.B. - 30 Mar 2008 04:59 GMT
>> [...]
>> The code has been rewritten using unmanaged code to get a significant
[quoted text clipped - 6 lines]
> implementation was C++, is the above statement meant to imply that you
> were using managed C++?

My apologies for the miscommunication.  The socket code and most
everything else is managed code.  The part that is not managed is the
code that convert the byte arrays to a class with explicit StructLayout
structures (managing DIS EntityState PDUs).

>> In running a profiler, it appears the code is processing the data as
>> fast as the OS is invoking the asynchronous callback.  As a test, I
[quoted text clipped - 4 lines]
> How do you know you are encountering an overflow?  Are you sure that you
> aren't losing datagrams due to some other reason?

Each time the receive callback is invoked, the code checks to see how
full the buffer is.  When it is close to 100%, we start noticing data
not being received.

>> Maybe it is the actual NIC we're using?  Or is it a limitation of
>> Windows XP and Windows 2003 Server?  This is a tough one to figure out.
>
> The "U" in "UDP" might as well stand for "unreliable".  UDP is
> inherently unreliable, and you _will_ lose datagrams eventually, no
> matter what you do.

Yes, it does happen.  However, when more than 25% of the packets are
getting lost, we start looking at the network for issues.

Thanks again for your help.  I think we're good to go for now.
Peter Duniho - 30 Mar 2008 01:08 GMT
> Each time the receive callback is invoked, the code checks to see how  
> full the buffer is.  When it is close to 100%, we start noticing data  
> not being received.

How do you check to see how full the buffer is?

> Yes, it does happen.  However, when more than 25% of the packets are  
> getting lost, we start looking at the network for issues.

25% is high, yes.  Still, that doesn't mean that it's simply a buffer size  
issue.

> Thanks again for your help.  I think we're good to go for now.

Somehow I suspect not.  But if you're satisfied with the solution, I guess  
that's your perogative.  Good luck.

Pete
O.B. - 31 Mar 2008 20:14 GMT
On Mar 29, 7:08 pm, "Peter Duniho" <NpOeStPe...@nnowslpianmk.com>
wrote:
> > Each time the receive callback is invoked, the code checks to see how
> > full the buffer is.  When it is close to 100%, we start noticing data
[quoted text clipped - 14 lines]
>
> Pete

Well, doing a Socket.Connect() on a UDP socket causes a Socket.Bind()
to throw a socket exception.  So it is not possible to Bind on a local
address in UDP *and* use Connect to specify a remote address at the
same time.  Oh well ... that's life.

Rate this thread:







Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.