This message was discovered on microsoft.public.dotnet.languages.csharp.
Responses highlighted in red are from those people who are likely to be able to contribute good, authoratitive information to this discussion. They include Microsoft employees, MVP's and others who IMHO contribute well to these kinds of discussions.
| Matthew Groch |
To All Networking/.NET/C# gurus out there:
Can anyone explain the behavior of what's happening under the covers when the following client intereacts with the following server (code below)? This code is basically a stripped down version of a system I'm trying to put together that is having major stability issues.
Basically, the client connects to the server and starts pouring information onto the socket connection in an asynchronous fashion. The server takes it's time processing the information it receives off of the socket connection. Eventually, the whole thing blows up... and when it blows up, I mean until I kill the server process, I can't use IE anymore, instant messager dies, PCAnywhere dies, etc..
Here's the exception that gets thrown server side:
Unhandled Exception: System.InvalidOperationException: AcceptCallback ---> Syste m.Net.Sockets.SocketException: An operation on a socket could not be performed b ecause the system lacked sufficient buffer space or because a queue was full at System.Net.Sockets.Socket.BeginSend(Byte[] buffer, Int32 offset, Int32 siz e, SocketFlags socketFlags, AsyncCallback callback, Object state) at Server.Server.HandleSocketAccept(IAsyncResult result) in v:\socketbuffer\s erver\class1.cs:line 65 at System.Net.Sockets.AcceptAsyncResult.AcceptCallback(Object stateObject, Bo olean Signaled) --- End of inner exception stack trace --- at System.Net.Sockets.AcceptAsyncResult.AcceptCallback(Object stateObject, Bo olean Signaled)
And, here's the code:
using System; using System.Net; using System.Net.Sockets; using System.Text;
namespace Server { public class Server { private AsyncCallback _acceptCallback;
private AsyncCallback _acceptSend;
private Socket _socket;
private byte[] _message;
public Server(int port) { string str = "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg" + "aldgh;elskghlskhglsghlshg;slghl;sgha;lgh;lahg;lshg;lshg;lshg";
Encoding encoding = Encoding.GetEncoding("iso-8859-1"); _message = encoding.GetBytes(str);
_acceptCallback = new AsyncCallback(this.HandleSocketAccept); _acceptSend = new AsyncCallback(this.HandleSendData);
_socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); _socket.SetSocketOption(SocketOptionLevel.Socket,SocketOptionName.ReuseAddress,1); IPEndPoint endPoint = new IPEndPoint(IPAddress.Any,port); _socket.Bind(endPoint); _socket.Listen(1); _socket.BeginAccept(_acceptCallback,_socket); }
private void HandleSocketAccept(IAsyncResult result) { Socket server = (Socket)result.AsyncState; Socket socket = server.EndAccept(result); // start test while (true) { socket.BeginSend(_message,0,_message.Length,SocketFlags.None,_acceptSend,socket); Console.WriteLine("Sent msg!"); } }
private void HandleSendData(IAsyncResult result) { Socket socket = null;
try { socket = (Socket)result.AsyncState; int numBytes = socket.EndSend(result); Console.WriteLine("wrote " + numBytes + " bytes!"); }
catch (Exception ex) { Console.WriteLine(ex.ToString()); } } }
public class Class1 { public static void Main(string[] args) { try { Server server = new Server(6969); Console.WriteLine("Listening!"); Console.ReadLine(); }
catch (Exception ex) { Console.WriteLine(ex.ToString()); } } } }
using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading;
namespace Client { public class Client { private AsyncCallback _acceptReceive;
private Socket _socket;
private byte[] _buffer;
public Client(int port) { _buffer = new byte[1024]; _acceptReceive = new AsyncCallback(this.HandleReceiveData); _socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp); _socket.Connect(new IPEndPoint(Dns.Resolve("localhost").AddressList[0],port)); _socket.BeginReceive(_buffer,0,_buffer.Length,SocketFlags.None,_acceptReceive,_socket); }
private void HandleReceiveData(IAsyncResult result) { Socket socket = null;
try { socket = (Socket)result.AsyncState; int numBytes = socket.EndReceive(result);
if (numBytes > 0) { Console.Write("."); Thread.Sleep(1000); } }
catch (Exception ex) { Console.WriteLine(ex.ToString()); } } }
class Class1 { public static void Main(string[] args) { Client client = new Client(6969); Console.WriteLine("Client started!"); Console.ReadLine(); } } }
|
|
| |
| |
| Jared Parsons [MSFT] (VIP) |
The basic problem here is that your server class is sending data and the client is not processing it. You'll notice that you're class Client only post a single BeginReceive(). After the first receive, it won't process any more data.
However your class Server is sending data at an extremely fast rate to the client and it is not waiting for confirmation inbetween sends. Eventually the data sent by the server will fill up the kernel buffer's on the client computer and then it will start backing up on the server computer. Eventually an error will get produced.
I'm not sure why the error is being thrown where it is though.
You have several options to prevent this error from occuring. 1) Don't send in a loop in the server. Instead send one time when the socket is accepted. Then in the EndSend call back, send your data again. This will prevent you from overflowing the buffers on the server. 2) Receive more than once in the client.
This problem you're seeing is partly associated with the internal workings of BeginReceive/EndReceive and BeginSend/EndSend. Under the hood, I believe these methods use I/O Completion ports. If you're curious about how that works take a look at this article.
http://msdn.microsoft.com/msdnmag/issues/1000/Winsock/
Please post back if can't get around this problem
-- Jared Parsons [MSFT] Click here to reveal e-mail address This posting is provided "AS IS" with no warranties, and confers no rights. OR if you wish to include a script sample in your post please add "Use of included script samples are subject to the terms specified at http://www.microsoft.com/info/cpyright.htm"
"Matthew Groch" <Click here to reveal e-mail address> wrote in message news:Click here to reveal e-mail address... [Original message clipped]
ss,1); [Original message clipped]
ket); [Original message clipped]
e,_socket); [Original message clipped]
|
|
| |
| |
| Matthew Groch |
Sorry, I should have pointed out in my previous post that I deliberately had the client not receive any more data after the first receive in order to reach the breakdown point more quickly. The example code I provided is definitely a contrived replica of the issue I'm working with.
In real life, I have multiple legacy front-end applications that receive high volumes of data from a single server. These front-end apps tend to process their incoming socket data slowly (they have to parse it before processing, etc..) Meanwhile, the server is receiving a high-volume data stream from a 3rd-party source and simply trying to broadcast it out to these clients as fast as it receives it. Eventually after some time (depending on the rate of the 3rd-party data stream), the server bombs out with the condition I describe in my previous post.
I am not very familiar with the front-end clients- in fact, I'm not for sure if they receive data off their socket connections in a synchronous or asynchronous fashion (I must investigate this). But, I'm under the belief that the fundamentals are the same: If the rate of sends on the socket is greater than the rate of receives on the socket (consistently, over a long enough period of time), then my current system will break.
I'll go ahead and follow up on that link you provided, Jared (thanks!). My end goal is to ensure that I can avoid the buffer overflow; ideally using asynchronous sockets. Any futher suggestions toward the point would be GREATLY appreciated. Thanks in advance-
"Jared Parsons [MSFT]" <Click here to reveal e-mail address> wrote in message news:<uEAuL$Click here to reveal e-mail address>... [Original message clipped]
|
|
| |
|
|
| |
| Adam W Root |
You've got your concepts mixed up. You are sending data too fast. The code you wrote is sending code in a fashion that SHOULD be synchronous, but you do it using asynchronous method calls. Here's some pseudocode:
mymethod() { BeginSend(); // now do something else!! you won't be held up by the previous call }
mysendcallback() { EndSend(); if (more data to send) BeginSend(); }
Hope this helps, I know it's vague, but it gives you the idea. Basically, you were trying to send, then send more before that send completed, then send more before either send completed, etc etc...
It worked for awhile, because the buffer slowly got more and more full, then it filled and crashed.
Good luck
Adam
"Matthew Groch" <Click here to reveal e-mail address> wrote in message news:Click here to reveal e-mail address... [Original message clipped]
ss,1); [Original message clipped]
ket); [Original message clipped]
e,_socket); [Original message clipped]
|
|
| |
|
|
|
|
|