I have a situation here.
I'm using System.Net.Sockets.Socket to read and send TCP messages.
Using the recursion for receiving the data and reading again new data.
void rcvTCP(IAsyncResult ar)
{
var socket = (Socket)ar.AsyncState;
try
{
var bytesRead = socket.EndReceive(ar);
if (bytesRead > 0)
{
var data = new byte[bytesRead];
Array.Copy(this.mBuffer, data, data.Length);
dataReceived(this, mMaster.SlaveAddress, data);
}
socket.BeginReceive(mBuffer, 0, mBuffer.Length, SocketFlags.None, new AsyncCallback(rcvTCP), socket);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
I'm sending messages from a device to my app, each 10ms, 8 bytes each message. I'm receiving the messages ok, so the "bytesRead" is 8, until a certain point when the app freezes randomly, and "bytesRead" is 768. When I look inside the data that came, I see that I have 96 messages in one.
I've read in the internet, like the messages are coming Sync instead of Async, so checking the "CompletedSinchronously" gives true at previous messages and this message also...
if (ar.CompletedSynchronously)
{
Debugger.Break();
}
I tried with TcpClient + NetworkStream instead of Socket(I know that TcpClient is pretty the same as Socket), and I have the same result.
Please help me. I want all the messages separated instead of collected, but I can't find any solution to this...
Any idea how to do this?
PS: I am already putting the flag - NoDelay to true.
FIX: For me the fix was splitting the collected messages after the receive, and running the splitting in a separate thread, so the UI does not freeze. Keep in mind, if you have a property used in different Threads, don't forget to use "lock".
Related
I am using Asynchronous TCP server/client communication. I have noticed in my log that the same client reconnects several times. However, it never shows that it was disconnected. My code has logging for both connection and disconnection. So why does readAsync stay in loop while the client has disconnected? Here is the code for your reference:
private async Task Accept(TcpClient client)
{
//get client information
string clientEndPoint = GetClientIPAddress(client);
log.Info("Client connected at " + clientEndPoint); //same client is connected several times in log
await Task.Yield ();
try
{
using (client)
using (NetworkStream stream = client.GetStream ())
{
byte[] dataReceived = new byte [100];
while (await stream.ReadAsync(dataReceived, 0, dataReceived.Length) != 0) //read input stream - 0=>end of stream is reached
{
//pass on data for processing
var task = ProcessData(dataReceived);
}
}
log.Info("Closing client connection " + clientEndPoint);//this line is never reached in log
if (client.Connected)
client.Close();
} //end try
catch (Exception ex)
{
log.Error(ex.Message);
log.Info("Closing client connection " + clientEndPoint);
if (client.Connected)
client.Close();
}
It looks like you may have a half-open problem. You should periodically write data to determine whether the socket is still connected; reads can detect graceful shutdowns but not half-open scenarios.
I describe the half-open problem more on my blog.
Did you check if TCP keep alive is set? That should detect if connection is broken.
Also, check if you got zero length bytes on receive, this means that connection is closed.
Edit: Keep Alive is standard method to check if connection is active, this means that one side sends small chunks of data to the other side periodically: http://en.wikipedia.org/wiki/Keepalive.
Many components have this feature already implemented. I've never used TcpClient class, but it must be some wrapper class for Socket over TCP and, as doc states, this class have exposed underlaying Socket (you can use Socket class for TCP also, but never mind). And this Socket have method SetSocketOption. So try:
client.Socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);
I have wrote a code to listen data on particular port in TCP mode.
Now the problem here is that the below code receives some data from the remote and after sometime it does not receive anything
I have check the wireshark and data is coming over there
I have check the TCPView, port (2-3 entries of same port is there) is open with the application but few port status stays as "ESTABLISHED" and one port is saying "LISTENING"
If i am checking the wireshark for missign data detail, then i found that remote IP-Port pair is stated as "ESTABLISHED" in TCPView but it cannot write anything in log file
My question is why the no data received in my application. Is there anything wrong in the code? I have tried every option which google can provide but there is no luck.
TcpListener tcpListenerDeviceResponse = new TcpListener(new IPEndPoint(IPAddress.Parse(localIP), 6005));
tcpListenerDeviceResponse.Start();
while (true)
{
using (TcpClient client = tcpListenerDeviceResponse.AcceptTcpClient())
{
// Get a stream object for reading and writing
using (NetworkStream stream = client.GetStream())
{
Socket skSource = client.Client;
int i;
var data2 = new byte[client.ReceiveBufferSize];
// Loop to receive all the data sent by the client.
while ((i = stream.Read(data2, 0, data2.Length)) != 0)
{
// Translate data bytes to a ASCII string.
string strResponse = System.Text.Encoding.ASCII.GetString(data2, 0, i);
// Insert the data in log text file
// process data
}
stream.Close();
}
// Shutdown and end connection
client.Close();
}
}
tcpListenerDeviceResponse.Stop();
One Reason could be Timeout!
Assuming Transmitting socket doesn't send data for more than Receiving socket's timeout, it will result in Timeout Error and will break the while loop and Close the socket.
This MSDN link might help you!
Also, I would suggest you to close the socket only if it is breaking while for other reasons except Timeout. If Timeout occurs, Go on reading again.
First things first, let me explain my situation: I'm working on a client and a server in C# which use socket for communication.
For practical reason, I use the asynchronous part of both socket to transmit binary serialized objects from the client to the server and vice-versa.
My problem is that when I send too much object at once, the receiver object "stack" into the buffer and when I try to unserialize the buffer content, it give me only one object.
My question is : How can I separate each object from a buffer ?
Here is my ReceiveCallback function :
private void ReceiveMessageCallback(IAsyncResult asyncResult)
{
Socket socket = (Socket)asyncResult.AsyncState;
try
{
int read = socket.EndReceive(asyncResult);
if (read > 0)
{
Log("Reception of " + read + " Bytes");
// Jumper is an object that I use to transport every message
Jumper pod = Common.Serializer.DeSerialize<Jumper>(this.readbuf);
Buffer.SetByte(this.readbuf, 0, 0);
socket.BeginReceive(this.readbuf, 0, this.readbuf.Length, SocketFlags.None, new AsyncCallback(ReceiveMessageCallback), socket);
//We fire an event to externalise the analyse process
Receiver(pod, socket);
}
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == System.Net.Sockets.SocketError.ConnectionReset)
{
socket.Close();
Log("Distant socket closed");
}
else
Log(ex.Message);
}
catch (Exception ex)
{
Log(ex.Message);
}
}
Deserialization will consume your buffer for one object, and will left 'read pointer' of the buffer at the start of the next object.
My suggestion would be to either:
move data from socket stream to some other (memory) buffer and deserialize from there, and have control over whole 'buffering' by hand
or
when you get a callback, call deserialize several times in a row, until you get an exception.
Second approach will most likely fail because nobody can guarantee that you will always get WHOLE objects in one go, since stream that is attached to a socket is a sequence of bytes, and it can be broken at any point.
Hope that makes some sense.
EDIT:
In fact, the proper thing to do this would be to encapsulate each 'message' (serialized object on sending) into a packet, in which for example you'll have a small header telling you LENGTH of the packet, and upon reception, you will read the socket stream until you have complete packet data, then serialize. And then the next packet, and so on.
EVEN MORE:
Say you send data at a rate of 1000 bytes at the sender side into the socket. On the receiving side, you'll probably NEVER get 1000 by 1000 bytes out of the socket, in fact you can expect that only under two conditions:
delay between each send is very large, and in between sends read occurs at receiver
pure accident
I am totally confused right now.
Edit: Okay, nevermind. The Python socket as well is starting to do it now.
Edit 2: Well, not quite sure if this is causing high CPU usage, but something randomly is. Is there an efficient way to figure out what is causing spikes in the usage? This project is a bit large and has various threads.
I have an asynchronous server that listens and waits for incoming connections, then keeps them alive and waits for the socket to flush and give the server data. It is only closed when the user wants the socket to be closed.
However, whenever I let a socket & stream stay connected, it starts to go haywire and starts sending empty data on an endless loop... it may take anywhere from 15 seconds to over a minute before it starts going wack. If I let it go for a really long time, it starts to cause really high CPU usage.
Aside from the high CPU usage, oddly enough, everything works as it should; messages are sent & received fine.
This is my read callback function:
protected void ReadCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.SocketHandle;
try
{
int bytesRead = (state.BytesRead += handler.EndReceive(ar)), offset = 0;
string line = m_Encoder.GetString(state.Buffer, 0, bytesRead);
if ( state.Buddy != null )
Console.WriteLine(state.Buddy.Address);
if (bytesRead > 0)
{
Console.WriteLine("!!!");
/* A complete request? */
if (line.EndsWith("\n") || line.EndsWith("\x00"))
{
string[] lines = line.Split('\n'); // ... *facepalm*
foreach (string ln in lines)
this.MessageReceieved(ln, state);
state.Buffer = new byte[StateObject.BUFFER_SIZE];
state.BytesRead = 0; // reset
}
/* Incomplete; resize the array to accommodate more data... */
else
{
offset = bytesRead;
Array.Resize<byte>(ref state.Buffer, bytesRead + StateObject.BUFFER_SIZE);
}
}
if (handler != null && handler.Connected )
handler.BeginReceive(state.Buffer, offset, state.Buffer.Length - offset, SocketFlags.None, new AsyncCallback(ReadCallback), state);
}
catch (SocketException)
{
if (state.Buddy != null)
state.Buddy.Kill();
else
handler.Close();
}
}
I know this is somehow caused by calling BeginReceive, but I don't know how else to keep the connection alive.
There is nothing in that code that can make it go haywire.
I do see some problems though.
Connection detection
No need to check if the socket is connected. You can detect disconnections in two ways in the receive callback:
Zero bytes is returned by EndReceive
An exception is being thrown.
I would recommend that the first thing you do after EndReceive is to check the return value and handle disconnect accordingly. It makes the code clearer.
Your code will currently do nothing if 0 bytes are received. The handler will just stop receiving and still think that the connection is open.
Buffer handling
Your buffer handling is very inneffecient. Do not resize the buffer every time. It will slow your server down a lot. Allocate a large buffer from start.
String handling
Don't build a string every time you receive something. Check inside the byte buffer after new line or null instead. THEN build a string, and only make it as large as needed. You might receive more bytes that just a message (for instance one and a half message)
Naturally, BeginReceive() will never end if there's no data.
MSDN suggests that calling Close() would abort BeginReceive().
However, calling Close() on the socket also performs a Dispose() on it, as figured out in this great answer, and consequently EndReceive() would throw an exception because the object is already disposed (and it does!).
How should I proceed?
It seems like this is by (the very dumb) design. You must have this exception thrown and caught in your code.
MSDN looks silent about it indeed, but if you look at the documentation of another asynchronous socket method, BeginConnect(), here's what we find:
To cancel a pending call to the
BeginConnect() method, close the
Socket. When the Close() method is
called while an asynchronous operation
is in progress, the callback provided
to the BeginConnect() method is
called. A subsequent call to the
EndConnect(IAsyncResult) method will
throw an ObjectDisposedException to
indicate that the operation has been
cancelled.
If it is the proper way of doing for BeginConnect, it is probably so for BeginReceive as well. This is certainly a poor design on the part of Microsoft's async API, because making the user necessarily throw and catch exception as a part of a normal flow would annoy the debugger. You have really no way to "wait" until the operation is completed, because Close() is what completes it in the first place.
I am surprised no one recommended using SocketOptions.
Once the stack has the send or receive operation it is bound by the socket options of the socket.
Use a small send or receive timeout and use it before the operation so you don't care if it's changed during that same operation to something shorter or longer.
This will cause more context switching but will not require closing the socket under any protocol.
For example:
1) Set a small timeout
2) Perform operations
3) Set timeout larger
This is similar to using Blocking = false but with an automatic timeout that you specify.
You can read my solution of this problem here(using comment of Pavel Radzivilovsky here):
UdpClient.ReceiveAsync correct early termination
For TCP socket connections, you can use the Connected property to determine the state of the socket before trying to access any disposed methods. Per MSDN:
"The Connected property gets the connection state of the Socket as of the last I/O operation. When it returns false, the Socket was either never connected, or is no longer connected."
Since it says "no longer connected" it implies that a Close() was previously called on the socket. If you check whether the socket is Connected at the start of the receive callback, there will be no exception.
In the ReceiveCallback I checked client.Connected within the try block.
Now, when data is received after BeginReceive, I can call client.Close();
This way, I do not see exceptions. I send modbus-TCP requests every 200mS, and get responses in time. The console output looks clean. I used a windows forms app, to test this.
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
if (client.Connected)
{
// Read data from the remote device.
state.dataSize = client.EndReceive(ar);
if (state.dataSize > 0)
{
Console.WriteLine("Received: " + state.dataSize.ToString() + " bytes from server");
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, state.dataSize));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BUFFER_SIZE, 0,
new AsyncCallback(ReceiveCallback), state);
state.dataSizeReceived = true; //received data size?
dataSize = state.dataSize;
buffer = state.buffer.ToArray();
dataSizeReceived = state.dataSizeReceived;
string hex = ByteArrayToString(state.buffer, state.dataSize);
Console.WriteLine("<- " + hex);
receiveDone.Set();
client.Close();
}
else
{
Console.WriteLine("All the data has arrived");
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
Console.WriteLine("Length: " + state.sb.Length.ToString());
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
Another solution would be to send "yourself" a "control message" using a socket bound to a different port. It's not exactly an abort, but it would end your async operation.
I was struggling with this as well but as far as I can tell using a simple boolean flag before calling .BeginReceive() will work as well (so there'll be no need for exception handling). Since I already had start/stop handling, this fix was a matter of one if statement (scroll down to the bottom of the OnReceive() method).
if (_running)
{
_mainSocket.BeginReceive(_data, 0, _data.Length, SocketFlags.None, OnReceive, null);
}
Should I have overlooked something with this approach, let me know!