.NET Forum / .NET Framework / New Users / May 2008
Issuing multiple Socket.BeginReceiveFrom() calls at one go
|
|
Thread rating:  |
Jonas Hei - 28 Jun 2005 15:52 GMT In all the samples that illustrate the use of Socket.BeginReceiveFrom(), once a BeginReceiveFrom() call is issued, then we wait for an incoming message, and then (a) either another BeginReceiveFrom() is issued from the AsyncCallback or (b) in the AsyncCallback sets an event which signals the main thread to continue and issue another BeginReceiveFrom().
My concern is that if we need to be highly scalable (say 100s or 1000s of incoming UDP messages) then this way isn't really going to cut it.
I've thought of quite a few optimizations such as allocating buffer space at startup (to avoid troubling GC with pinned memory) and also posting the incoming message to a local queue and processing it later and also playing with ThreadPool.SetMinThreads to setup optimum values.
My question is:
Is it possible to issue multiple calls to Socket.BeginReceiveFrom() at one go? If yes, what is the maximum number? I've tried this with 20 or so and it seems to work fine. I've illustrated the technique in the code below. Any comments?
public class Communicator { Socket skt = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); private Thread listenerThread; int initialListeners; public Communicator() { } public void Start(int initialNumberOfListeners) { initialListeners = initialNumberOfListeners; listenerThread = new Thread(new ThreadStart(Listen)); listenerThread.Start(); } private void Listen() { IPEndPoint localEndPoint = new IPEndPoint( IPAddress.Parse("0.0.0.0"), 9020); skt.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, 65536); skt.Bind(localEndPoint);
StateObject[] so2 = new StateObject[initialListeners]; for(int i=0; i<initialListeners; i++) { so2[i] = new StateObject(4096); so2[i].workSocket = skt; skt.BeginReceiveFrom( so2[i].buffer, 0, so2[i].BufferSize, 0, ref so2[i].tempRemoteEP, new AsyncCallback(ReceiveFromCallback), so2[i]); }
}
public void Stop() { bStop = true }
public void ReceiveFromCallback(IAsyncResult ar) { try { StateObject so = (StateObject) ar.AsyncState; Socket listenerSocket = so.workSocket;
StateObject newst = new StateObject(4096); newst.workSocket = listenerSocket; listenerSocket.BeginReceiveFrom( newst.buffer, 0, newst.BufferSize, 0, ref newst.tempRemoteEP, new AsyncCallback(ReceiveFromCallback), newst);
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); EndPoint tempRemoteEP = (EndPoint)sender; int read = listenerSocket.EndReceiveFrom( ar, ref tempRemoteEP);
if(read > 0) { so.sb.Append(Encoding.ASCII.GetString( so.buffer, 0, read)); string strContent; strContent = so.sb.ToString(); //post strContent to a Queue for later processing } } catch(ObjectDisposedException) { } }
}
public class StateObject { public Socket workSocket = null; public int BufferSize; public byte[] buffer = null; public StringBuilder sb = new StringBuilder(); public StateObject(int buffersize) { BufferSize = buffersize; buffer = new byte[BufferSize]; } public EndPoint tempRemoteEP = (EndPoint)(new IPEndPoint(IPAddress.Any, 0)); }
"Peter Huang" [MSFT] - 29 Jun 2005 04:50 GMT Hi
Because one socket will have one receive buff, so even multiple threads is waiting on a socket, in the mean time, there will be just one thread is do the receive job. Also if we create multiple threads to wait for the socket data, it is hard to do the control in the program, because we can not guarantee in certian time, which thread is arranged receiving the job. So maybe some time we find that more than one thread is working, that is because after do the receive job, the thread may do something else, and now another UDP is incoming, so another thread is receiving the data. That is to say, in fact the data receiving is serialized for one socket.
So I think your code seems OK, but we do not specifed multiple thread at the start. We just set the ReceiveFromCallback in the ReceiveFromCallback after we receive the data.
Best regards,
Peter Huang Microsoft Online Partner Support
 Signature Get Secure! - www.microsoft.com/security This posting is provided "AS IS" with no warranties, and confers no rights.
Jonas Hei - 29 Jun 2005 12:11 GMT Sorry I don't exactly understand your suggestions. It would be nice if you could elaborate a little.
Basically by dispatching multiple Socket.BeginReceiveFrom() calls I am trying to achieve better performance (or scalability - just to increase the sheer nubmer of UDP messages my application can receive per second).
My reasoning was that if I issue just one Socket.BeginReceiveFrom() call and then issue another call only after one incoming message has arrived, then I thought that if my large number of incoming messages are being received then there is a chance that my application would miss a few. I guess I read somewhere that windows can only queue upto 5 messages in the receive buffer. Is that correct?
If yes, then if various devices are bombarding hundreds (or thousands) of UDP messages per second at my server then there is this risk that this buffer of 5 messages will become full and some messages from this buffer might get discarded (by OS) before my code an issue another Socket.BeginReceiveFrom() call.
Does that make any sense? Am I on the right track here?
Peter Huang [MSFT] wrote:
> Hi > [quoted text clipped - 21 lines] > Get Secure! - www.microsoft.com/security > This posting is provided "AS IS" with no warranties, and confers no rights. "Peter Huang" [MSFT] - 30 Jun 2005 09:53 GMT Hi
I think there may be some confusion, in the TCP connection, if we have a listener. Then it will be a fix connectors count, e.g. 5, when the 6th connector arrived, but none of 5 connector is accepted, then the 6th will be disposed.
But for the UDP receiver, we do have a buffer, it will buffer the packet. Because the UDP package will be read per packet, so even there are more than one packet in the buff, we can only read one every time. The reading process is similar with below. e.g. There are 5 threads, ABCDE. A begin to receive-->Lock the buff memory(in the mean time, the other thread can not lock it)--->read memory--->unlock( in the process the other ones can not access to the buff)
Best regards,
Peter Huang Microsoft Online Partner Support
 Signature Get Secure! - www.microsoft.com/security This posting is provided "AS IS" with no warranties, and confers no rights.
sunghoon park - 13 May 2008 01:25 GMT Hi Peter!
I am try to build an application to play audio/video stream using DirectX and data coming from UDP Socket. My problem is that I have a garbage data at the fist 11 bytes. My code is not so different from his. Few things are different; 1) built by .net vc 2003 2) did not create multi-thread
Following is my code;
static IPEndPoint __gc *ipesender = new IPEndPoint(IPAddress::Any, 0); static EndPoint __gc *epsender; event() { try { Socket __gc *s = new Socket(AddressFamily::InterNetwork, SocketType::Dgram, ProtocolType::Udp); IPEndPoint __gc *ipendpoint = new IPEndPoint(IPAddress::Any, 1234);
MxL_UI_StateObject __gc *so1 = new MxL_UI_StateObject(1504); so1->workSocket = s; System::IAsyncResult *re1 = s->BeginReceiveFrom(AVbuff, 0, AVbuff->get_Length(), SocketFlags::None, &epsender, new AsyncCallback(0, &MxL_UI_Main::OnReceive), so1); } catch(...){} }
static void OnReceive(IAsyncResult *ar) { try { MxL_UI_StateObject __gc *so = __try_cast<MxL_UI_StateObject*>(ar->AsyncState) ; Socket __gc *listenerSocket = so->workSocket;
MxL_UI_StateObject __gc *newst = new MxL_UI_StateObject(1504); newst->workSocket = listenerSocket; System::IAsyncResult *re = listenerSocket->BeginReceiveFrom(newst->buffer, 0, newst->BufferSize, SocketFlags::None, &newst->tempRemoteEP, new AsyncCallback(0, &MxL_UI_Main::OnReceive), newst);
IPEndPoint __gc *sender = new IPEndPoint(IPAddress::Any, 0); EndPoint __gc *tempRemoteEP = __try_cast<EndPoint*>(ipesender); int read = listenerSocket->EndReceiveFrom(ar, &tempRemoteEP);
if(read > 0) { //?? how to play video->play(newst->buffer); } }
My questions are; 1) how to play streaming data using DirectX. It is very simple to play a file but I can not figure out playing streaming data. 2) My understanding is that OnReceive function is called by BeginReceiveFrom function when data arrived from network device. Is that correct? Could you explain more detail? 3) In order to play sreaming data, do I need 2 or more buffers that a thread passes those buffers to DirectX to play? Do you have any idea for this?
Any suggestion or idea will be appreciated. Thanks
url:http://www.ureader.com/msg/14151867.aspx
Free MagazinesGet 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 ...
|
|
|