Confusing System.SocketException thrown on a call to BeginReceive - c#

I've got an exception (System.SocketException) being thrown on the (I believe, second call to System.Net.Sockets.Socket.BeginReceive) that I do not understand why is being thrown. I'm trying to receive, and respectively append data that is received to a per-client MemoryStream object. This results in the received event never being fired, and some data not appended to the stream.
static void EndReceive(IAsyncResult ar)
{
// our client socket
var client = (Client)ar.AsyncState;
// amount of bytes received in this call (usually 1024 for buffer size)
var received = client.socket.EndReceive(ar);
if (received > 0)
{
// append to memorystream
client.stream.Write(client.buffer, 0, received);
}
else
{
// raise event done
ClientSent(client, client.stream.ToArray());
// clear out the memorystream for a new transfer
client.stream.SetLength(0L);
}
try
{
// continue receiving
client.socket.BeginReceive(client.buffer, 0, client.buffer.Length, SocketFlags.None, (AsyncCallback)EndReceive, client);
}
catch (SocketException socketException)
{
// error thrown every single time:
// System.Net.Sockets.SocketException: 'A request to send or receive data was disallowed because the socket
// is not connected and (when sending on a datagram socket using a sendto call) no address was supplied'
return;
}
catch (ObjectDisposedException disposedException)
{
return;
}
}

I don't know what caused this particular error. But after some tinkering I got the EndReceive method working correctly. Here's my new design:
static void EndReceive(IAsyncResult ar)
{
var client = (Client)ar.AsyncState;
var received = 0;
try
{
received = client.socket.EndReceive(ar);
}
catch (SocketException ex)
{
client.socket.BeginDisconnect(false, (AsyncCallback)EndDisconnect, client);
}
if (received > 0)
{
client.stream.Write(client.buffer, 0, received);
if (client.socket.Available == 0)
{
var sent = client.stream.ToArray();
client.stream.SetLength(0L);
Console.WriteLine("Client sent " + sent.Length + " bytes of data");
}
}
try
{
client.socket.BeginReceive(client.buffer, 0, client.buffer.Length, SocketFlags.None, (AsyncCallback)EndReceive, client);
}
catch (SocketException socketException)
{
return;
}
catch (ObjectDisposedException disposedException)
{
return;
}
}

Related

UWP StreamSocket client not receiving response after larger data transfer

I have a WPF 'server' app using a socket, with a UWP 'client' app using StreamSocket. I can transfer small amounts of data fine, but if I try and send a 288kb file, the file is received fine by the WPF app but the UWP app never receives the response.
WPF code:
In the ReadCallback method, the content is sent in the format of command;printername{data}. The data is all received fine but the Send method called before processing the data is not received.
public void Start()
{
Task.Run(() =>
{
var ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
var ipAddress = ipHostInfo.AddressList.FirstOrDefault(x =>x.AddressFamily == AddressFamily.InterNetwork);
var localEndPoint = new IPEndPoint(ipAddress, Settings.Default.PrintPort);
listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
IsRunning = true;
while (true)
{
// Set the event to nonsignaled state.
AllDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(
AcceptCallback,
listener);
// Wait until a connection is made before continuing.
AllDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
});
}
public void AcceptCallback(IAsyncResult ar)
{
if(!IsRunning) return;
// Signal the main thread to continue.
AllDone.Set();
// Get the socket that handles the client request.
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject {WorkSocket = handler};
handler.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
ReadCallback, state);
}
public static void ReadCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.WorkSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.Sb.Append(Encoding.ASCII.GetString(
state.Buffer, 0, bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
var content = state.Sb.ToString();
if (content.IndexOf("<EOF>") > -1)
{
content = content.Remove(content.IndexOf("<EOF>"));
if (content.StartsWith("PrintFile"))
{
if (!content.Contains("{"))
{
Send(handler, "false");
return;
}
var parts = content.Substring(0, content.IndexOf('{')).Split(';');
if (string.IsNullOrEmpty(parts[1]))
{
Send(handler, "false");
return;
}
// This send never gets received
Send(handler, "true");
//But the file is printed
var base64 = content.Substring(content.IndexOf('{') + 1);
base64 = base64.Remove(base64.LastIndexOf('}'));
var doc = new Spire.Pdf.PdfDocument(Convert.FromBase64String(base64));
doc.PrintSettings.PrinterName = parts[1];
doc.Print();
}
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.Buffer, 0, StateObject.BufferSize, 0,
ReadCallback, state);
}
}
}
catch
{
//Ignore
}
}
private static void Send(Socket handler, String data)
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
SendCallback, handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
UWP Code:
public bool PrintFlle(string printer, string base64)
{
try
{
var result = Send($"PrintFile;{printer}{{{base64}}}<EOF>").Result;
return bool.TryParse(result, out var b) && b;
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
finally
{
socket.Dispose();
}
}
private async Task<string> Send(string input)
{
try
{
socket = new StreamSocket();
await socket.ConnectAsync(HostName, App.LocalSettings.Values["PrintPort"] as string);
using (Stream outputStream = socket.OutputStream.AsStreamForWrite())
{
using (var streamWriter = new StreamWriter(outputStream))
{
await streamWriter.WriteLineAsync(input);
await streamWriter.FlushAsync();
}
}
using (Stream inputStream = socket.InputStream.AsStreamForRead())
{
using (StreamReader streamReader = new StreamReader(inputStream))
{
var output = await streamReader.ReadLineAsync();
socket.Dispose();
return output;
}
}
}
catch (Exception e)
{
socket.Dispose();
return "";
}
}

Determine end of message in socket stream

I have a project with a server and a client using asynchronous socket connections.
I want to transmit an object from server to client. Unfortunately I have the problem, that sometimes the object isn't fully transmitted in one go. Therefore I need a way to determine when an object was fully transmitted. So I added a four-byte-head to the data transmitted to tell, how long the stream will be.
Server
private void Send(Socket handler, Packet packet)
{
byte[] byteData = ByteHelper.Serialize(packet).Data;
byte[] byteDataLength = BitConverter.GetBytes(byteData.Length);
byte[] transmissionData = new byte[byteDataLength.Length + byteData.Length];
byteDataLength.CopyTo(transmissionData, 0);
byteData.CopyTo(transmissionData, byteDataLength.Length);
if (debug)
{
Status = "Sending "+packet.Type+"-packet to client.";
}
try
{
handler.BeginSend(transmissionData, 0, transmissionData.Length, 0, new AsyncCallback(SendCallback), handler);
}
catch (Exception ex)
{
Status = "[EXCEPTION]" + ex.Message.ToString();
}
}
The client receives the stream and evaluates the first four bytes to create a StateObject which has the right size. But I have the feeling that this is not really a good way to solve my problem. Is there a better way to do this?
Client
private void ReceiveCallback(IAsyncResult ar)
{
StateObject state = (StateObject)ar.AsyncState;
try
{
Socket client = state.workSocket;
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
do
{
state = AdjustState(state);
if (state != null)
{
if (state.buffer.Length == state.bufferSize)
{
ProcessPacket(state);
receiveDone.Set();
}
}
else
{
receiveDone.Set();
}
}
while (state != null && state.tempBuffer.Length >= state.bufferSize);
if (state != null)
{
client.BeginReceive(state.tempBuffer, 0, state.tempBuffer.Length, 0, new AsyncCallback(ReceiveCallback), state);
}
}
}
catch (Exception ex)
{
MessageBox.Show("ReceiveCallback: " + ex.ToString(), "Client-Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private static StateObject AdjustState(StateObject state)
{
StateObject tempState = state;
if (tempState.tempBuffer.Length >= 4)
{
byte[] sizeBytes = tempState.tempBuffer.Take(4).ToArray();
int bufferSize = BitConverter.ToInt32(sizeBytes, 0);
if (bufferSize == 0)
{
return null;
}
byte[] temp = tempState.tempBuffer.Skip(4).ToArray();
Socket tempSocket = tempState.workSocket;
tempState = new StateObject(bufferSize);
tempState.BufferSet();
if (temp.Length >= bufferSize)
{
tempState.buffer = temp.Take(bufferSize).ToArray();
tempState.tempBuffer = temp.Skip(bufferSize).ToArray();
}
tempState.workSocket = tempSocket;
}
return tempState;
}
Solution
Thanks to usr I've changed the bytesRead-Part in the ReceiveCallbackCode of the client to this. It seems to work now.
if (bytesRead > 0)
{
if (!state.bufferSet)
{
state = AdjustState(state);
client.BeginReceive(state.buffer, 0, state.bufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{
if (state.buffer.Length == state.bufferSize)
{
ProcessPacket(state);
receiveDone.Set();
}
else
{
client.BeginReceive(state.buffer, state.buffer.Length, state.bufferSize - state.buffer.Length, 0, new AsyncCallback(ReceiveCallback), state);
}
}
}
You are not making use of the return value from EndReceive (bytesRead). It signals how many bytes were received.
And in case bytesRead == 0 you just do nothing which is probably not a proper response to the connection having ended.
And then, there is this unsynchronized busy-loop:
while (state != null && state.tempBuffer.Length >= state.bufferSize);
That's going to burn one CPU core for each client connection. Must solve this differently.

WaitOne(timeout) after exception

I'm currently working on an application that reads dat from a socket.
I was curious, if I have a readDone.WaitOne(600000) with a larger than normal timeout, what happens if the readDone.Set() is never called in my ReadCallBack method due to an exception in the callback method?
Does it wait for the entire duration of the timeout or does it continue excecuting the main thread by handling the exception which is defined outside the ReadcallBack?
EDIT
Here is an example to explain what I mean:
public void SendAndReceive(Message message)
{
try
{
IPAddress ipAddress = IPAddress.Parse(this.host.Address);
IPEndPoint remoteEP = new IPEndPoint(ipAddress, this.host.Port);
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne(host.Timeout);
message.State = MessageState.SENDING;
Send(client, message.Request);
if (sendDone.WaitOne(120000)) // TIMEOUT SET TO 2 MINUTE
{
// Request sent successful. Now attempt to retrieve response.
message.State = MessageState.READING;
Receive(client);
}
else
{
message.State = MessageState.SEND_ERROR;
message.ErrorMessage = "Timeout while sending request to socket.";
}
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Close();
}
}
catch (Exception ex)
{
LogManager.ExceptionHandler(ex);
message.ErrorMessage = ex.Message;
message.State = MessageState.EXCEPTION;
}
}
private void Send(Socket client, String data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
System.IO.MemoryStream dataStream = new System.IO.MemoryStream();
dataStream.WriteByte(1);
dataStream.Write(byteData, 0, byteData.Length);
dataStream.WriteByte(3);
client.BeginSend(dataStream.GetBuffer(), 0, dataStream.GetBuffer().Length, 0, new AsyncCallback(SendCallback), client);
}
private void SendCallback(IAsyncResult ar)
{
try
{
var client = (Socket)ar.AsyncState;
client.EndSend(ar);
// Throw exception before .Set can is called
throw new Exception("test");
sendDone.Set();
}
catch (Exception ex)
{
}
}
So to clarify:
sendDone.WaitOne(120000) is set to timeout after 2 minutes, which means, is .Set() is not called in 2 minutes the main thread will continue to execute. My question is, if there is and exception in the SendCallBack before it can call the .Set(), will the sendDone still hold up the main thread for 2minutes, or will it automatically jump to the try catch in SendAndReceive method?
So I tested this, and if an exception is thrown the WaitOne() is cancelled.

TCP SOCKET : Stream is sent/received twice in asynchronous operation

I'm currently working on asynchronous TCP program but I'm having the following issue:
-When the Server sends some stream , the Client first receives an empty buffer and then it receives the stream.
-After the first stream sending,if I'm sending another stream the client's buffer contains the first stream sent and the current
stream.
-If I'm sending another stream, the buffer will contain the stream I sent before and the current one..and so on..
This is really annoying and I don't know where's the problem.
Here is my CLIENT Code:
Socket CLIENT;
byte[] _buffer;
private void button1_Click(object sender, EventArgs e)
{
Start();
}
void Start()
{
CLIENT = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
CLIENT.BeginConnect(IPAddress.Parse("the IPaddress"), 1234, new AsyncCallback(ConnectionCallBack), null);
}
private void ConnectionCallBack(IAsyncResult ar)
{
try
{
CLIENT.EndConnect(ar);
_buffer = new byte[CLIENT.ReceiveBufferSize];
CLIENT.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), null);
}
catch (Exception Er)
{
MessageBox.Show("[[[[ERROR:1]]]]=>" + Er.Message);
}
}
private void ReceiveCallBack(IAsyncResult ar)
{
try
{
int lenght = CLIENT.EndReceive(ar);
if (lenght == 0) { return; }
Array.Resize(ref _buffer, lenght);
string stream = ASCIIEncoding.ASCII.GetString(_buffer);
Array.Resize(ref _buffer, CLIENT.ReceiveBufferSize);
CLIENT.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), null);
}
catch (Exception ex) { MessageBox.Show("[[[[hoERROR:2]]]]=>" + ex.Message); }
}
Here is the server:
private void button2_Click(object sender, EventArgs e)
{
try
{
Socket socket = (Socket)listW.SelectedItems[0].Tag; //contains the socket
socket.BeginSend(_buffer,0,_buffer.Length,SocketFlags.None,new AsyncCallback(SendingCallBack),socket);
ServerSocket.BeginAccept(new AsyncCallback(AcceptCallBack),null);
}
catch (Exception er) { MessageBox.Show("[[[[ERROR:]]]]=>" + er.ToString()); }
}
private void SendingCallBack(IAsyncResult ar)
{
try
{
Socket socket = (Socket)ar.AsyncState;
_buffer = ASCIIEncoding.ASCII.GetBytes(tx1.Text);
socket.BeginSend(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(FinalCallBack),socket);
}
catch (Exception er) { MessageBox.Show("[[[[ERROR:3]]]]=>" + er.ToString()); }
}
private void Final(IAsyncResult ar)
{
Socket client = ar.AsyncState as Socket;
client.EndSend(ar);
}
I think you have a few problems. One seems to be the stream in ReceiveCallback. You get a string from the buffer then do nothing with it. Resizing your buffer down then resizing if back up to the original size seems like a waste. Might was well make a copy of the data then call GetString and you can leave your buffer alone.
In your server, you call BeginSend to send _buffer, when that completes you call BeginSend again in SendingCallback with the binary representation of tx1.Text but you don't call EndSend, when that completes you call EndSend on the 2nd BeginSend; but still haven't called it for the 1st.

Getting Error thrown when TCP connect lost

I have a block of code that "listens" on a TCP port and just sends an string back no matter what is sent. The issue is the client side is just testing to see if the port is active then disconnecting. At which point I get an error thrown.
Cannot access a disposed object
Object name: 'System.Net.Socket.NetworkSystem'
I think the issue is that this code is on a thread and when the connection closes the while loop references a disposed object... how should I prevent the error from firing when the client closes the connection?
//Cretae listener to accept client connections
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] rcvBuffer = new byte[BUFSIZE]; // Receive buffer
int bytesRcvd; // Received byte count
while (ServiceRunning) // Run forever, accepting and servicing connections
{
try
{
// Receive until client closes connection, indicated by 0 return value
int totalBytesEchoed = 0;
//I THINK THIS IS WHERE THE PROBLEM IS .. THE CLIENTSTREAM.READ???
while (((bytesRcvd = clientStream.Read(rcvBuffer, 0, rcvBuffer.Length)) > 0) && (ServiceRunning))
{
clientStream.Write(responseBytes, 0, responseBytes.Length);
WriteEventToWindowsLog("GSSResponderService", "Received "+System.Text.Encoding.UTF8.GetString(rcvBuffer), System.Diagnostics.EventLogEntryType.Information);
totalBytesEchoed += bytesRcvd;
}
WriteEventToWindowsLog("GSSResponderService", "Responded to " + totalBytesEchoed.ToString() + " bytes.", System.Diagnostics.EventLogEntryType.Information);
// Close the stream and socket. We are done with this client!
clientStream.Close();
tcpClient.Close();
}
catch (Exception e)
{
//THIS IS GETTING TRIGGERED WHEN A CONNECTION IS LOST
WriteEventToWindowsLog("GSSResponderService", "Error:" + e.Message, System.Diagnostics.EventLogEntryType.Error);
clientStream.Close();
tcpClient.Close();
break;
}
}
}
According to MSDN, Read method of NetworkStream class throws IOException when the underlying Socket is closed and ObjectDisposedException when the NetworkStream is closed or there is a failure reading from the network. The same exceptions are thrown by Write method.
Therefore it shoud be enough to catch these 2 exception types and take appropriate action in exception handlers.
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] rcvBuffer = new byte[BUFSIZE]; // Receive buffer
int bytesRcvd; // Received byte count
while (ServiceRunning) // Run forever, accepting and servicing connections
{
try
{
// Receive until client closes connection, indicated by 0 return value
int totalBytesEchoed = 0;
try
{
while (((bytesRcvd = clientStream.Read(rcvBuffer, 0, rcvBuffer.Length)) > 0) && (ServiceRunning))
{
clientStream.Write(responseBytes, 0, responseBytes.Length);
WriteEventToWindowsLog("GSSResponderService", "Received "+System.Text.Encoding.UTF8.GetString(rcvBuffer), System.Diagnostics.EventLogEntryType.Information);
totalBytesEchoed += bytesRcvd;
}
}
catch(IOException)
{
//HERE GOES CODE TO HANDLE CLIENT DISCONNECTION
}
catch(ObjectDisposedException)
{
//HERE GOES CODE TO HANDLE CLIENT DISCONNECTION
}
WriteEventToWindowsLog("GSSResponderService", "Responded to " + totalBytesEchoed.ToString() + " bytes.", System.Diagnostics.EventLogEntryType.Information);
// Close the stream and socket. We are done with this client!
clientStream.Close();
tcpClient.Close();
}
catch (Exception e)
{
WriteEventToWindowsLog("GSSResponderService", "Error:" + e.Message, System.Diagnostics.EventLogEntryType.Error);
clientStream.Close();
tcpClient.Close();
break;
}
}
}

Categories

Resources