Socket.BeginSendTo and Socket.BeginSendFrom on a single Socket instancefrom multiple threads

J

Jonas Hei

Is it safe to call socket.BeginSendTo and socket.BeginSendFrom on a
single instance of Socket from two different threads running simultaneously?

This is required because I need to listen on a certain URI [IP:port] and
I need to send outgoing messages from that local socket [IP:port]

something like this:
public class Communicator {
Socket skt = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp );
private Thread listenerThread;
private Thread sendThread;
public Communicator() { }
public void Start() {
listenerThread = new Thread(new ThreadStart(Listen));
sendThread = new Thread(new ThreadStart(Send));
listenerThread.Start();
sendThread.Start();
}
private void Listen() {
while(!bStop) {
skt.BeginReceiveFrom(..);
//wait for AsyncCallback to be called
//using ManualResetEvent for this
}
}
private void Send() {
while(!bStop) {
//send all queued messages
skt.BeginSendTo(..);
//wait for AsyncCallback to be called - that would send an event
//using ManualResetEvent for this
}
}
public void Stop() {
bStop = true
}
}
 
P

Peter Huang [MSFT]

Hi

I think it will work in theory , because the receive and send buff is
independent.
So when we send in thread A, the thread A will access socket send buff,
when we receive in Thread B, the thread B will access socket receive buff.
But why you need to do that, I think one more socket declaration will not
take much system resource.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jonas Hei

The reason I have not used another socket declaration is that one the
primary requirements is to listen for incoming messages on a certain
socket (IPAddress:portNumber) and to send the outgoing message from that
same port.

So I have to use one socket instance.

One possibility is to use two different socket declarations (with
SO_REUSEADDR or SocketOptionName.ReuseAddress). It probably does have
some negative aspects (document appears to recommend
SocketOptionName.ExclusiveAddressUse for safety).

Your thoughts or recommendations?
 
P

Peter Huang [MSFT]

Hi

The second approach is strongly not recommended, because we can not
guarantee the incomming data will be in certain fix socket, it is somewhat
randomly.
Also I just wonder why you wants the sender to use the same UDP port,
because UDP is connectionless unlike TCP is connection-oriented, so why not
send the UDP package at a random port.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jonas Hei

Peter,

Thanks for your replies. They've been very helpful.

The reason we need to send messages from the same port on which we
receive messages is because of firewall (NAT/PAT) that sits between the
devices that are sending data and my application which receives data and
responds back to the devices.

The remote devices (they are sitting inside a firewall and they have
private ip addresses) initiate the communication by sending a message.
Their firewall does the Port Address Translation and forwards the
message to my application (which is sitting outside the firewall on
public network). So if my application was receving messages on a certain
address (say 192.20.81.130:48000) then my application HAS TO send back a
message from 192.20.81.130:48000 - only then the firewall will allow it
to be forward to the device that initially sent the message.

By the way, it would be nice if you could explain me the downsides of
using SocketOptionName.ReuseAddress.
One advantage I have with that is that I can create two socket instances
- bind them both to 192.20.81.130:48000. And then use one for sending
messages and another to receive messages. That way, I do not have to
worry about the thread-safety of instance methods of Socket Class.

Your views?
 
P

Peter Huang [MSFT]

Hi

Here is document about SO_EXCLUSIVEADDRUSE and SO_REUSEADDR. .NET socket
is a wrap for win32 socket.

In the case where the first bind sets no options or SO_REUSEADDR, and the
second bind performs a SO_REUSEADDR, the second socket has overtaken the
port and behavior regarding which socket will receive packets is
undetermined. SO_EXCLUSIVEADDRUSE was introduced to address this situation.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/win
sock/using_so_exclusiveaddruse.asp

Use of the ReuseAddress has two concerns.
1. It may cause security issue, as the document above, if we set a socket
is not SO_EXCLUSIVEADDRUSE, so other low privilege app will set their
socket to listen on the same port.
2. As the document above, behavior regarding which socket will receive
packets is undetermined.

Since the winsock is an implement of BSD socket family, The SO_REUSEADDR is
used to compatible with the BSD socket.
Also for a common C/S app, the procedure should be as follows.
1. client send
2. server recv
3. server send
4. client recv.

So it is not necessary to do the resv and send in the mean time.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
J

Jonas Hei

Peter said:
Also for a common C/S app, the procedure should be as follows.
1. client send
2. server recv
3. server send
4. client recv.

So it is not necessary to do the resv and send in the mean time.

Peter, thanks for the details you've given so far - they've been very
helpful.

I would need to send and receive from multiple thread at the same time.
If I use two different sockets instances (via SO_REUSEADDR) then I run
the risks (security - undefined behaviour for receiving messages).
If I use one socket instance but use different threads for sending and
receiving messages then I run risks (due thread safety).

I reason I would need to send and receive at the same time is because my
application has to deal with thousands of clients. Each of those clients
will send messages to my application. In my application there would be
messages queued to send to them.
So in any given time (say any given second) my application would have to
receive messages from hundreds of clients. And it would have to send
messages to hundreds of clients.


What I don't really understand so far is that why
Socket.BeginReceiveFrom(), EndReceiveFrom(), BeginSendTo(), and
EndSendTo() not thread safe.

Even in the normal MSDN samples for BeginReceiveFrom() - multiple
threads do end up using a single socket instance. That is because:
1. First thread issues 1st call to BeginReceiveFrom()
2. once data is ready the system calls AsyncCallback.
3. In the AsyncCallback, (in the MSDN sample) an event is set.
The setting of this event results in the First thread issuing
another BeginReceiveFrom(). But while the First thread is
issuing this BeginReceiveFrom(), the i/o completion thread
that system used to call AsyncCallback is issuing an
EndReceiveFrom(). In the sample I've not seen any locking being
done to access the socket.

So wouldn't it be safe for me to issue multiple BeginReceiveFrom()s from
one thread. And another bunch of multiple BeginSendTo()s from another
thread while all the i/o completion threads call the relevant
EndReceiveFrom()s and EndSendTo()s. Can I do all that without bothering
to lock before accessing this instance of Socket class?
 
P

Peter Huang [MSFT]

Hi

Thanks for your quickly reply!

From the document, the socket class's Thread Safety is as below.
Any public static (Shared in Visual Basic) members of this type are thread
safe. Any instance members are not guaranteed to be thread safe.
Socket Class
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/
frlrfsystemnetsocketssocketclasstopic.asp

I do not think multiple thread will improve the I/O much, because the
underlying I/O is serialize if we do with a single socket.

Also can you show a link about the sample?


Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 
P

Peter Huang [MSFT]

Hi

This is a TCP Server, which is somewhat different from UDP protocol.
In TCP, we need a listener socket to listen on certain server port and then
call Accept to try to get the attempted incomming connection.
It then will return a new socket which will handle the data send/recv.
So actually there will be a socket per thread to handle the send/recv.

As for the listener socket, this is a asynchronous operation. For common
synchronous scenario, the steps is, Bind--->Accept( then send/recv on the
accept returned socket). Bacause the time is common very little to accept a
connection and we need to call EndAccept in the new thread, so we need to
pass the listener socket to the new thread and call allOne.Set to signal
the mail thread. I think this just a strategy to speed creating new thread
to handle the incomming connection. But the data send/recv is working on
every new accepte returned socket.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top