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.
Related
The code below creates socket server and client
I start the server and if I start one after the other the clients it works fine
If I start three clients immediately, then for one or more clients the BeginAccept event is not fired
The results bellow are after executing the code bellow
Server Started
Server is waiting for a connection...
Client 0.0.0.0:6352 requests connection
Client 0.0.0.0:6353 requests connection
Client 127.0.0.1:6351 requests connection
Client 127.0.0.1:6351 connected
Client 127.0.0.1:6352 connected
Client 127.0.0.1:6353 connected
ServerOnClientConnection Client: 127.0.0.1:6351
Server is waiting for a connection...
ServerOnClientConnection Client: 127.0.0.1:6353
code follows
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace Test {
public class TestSockets {
#region server
Socket serverSocket;
bool serverIsAlive;
public ManualResetEvent waitForConnection = new ManualResetEvent(false);
private Encoding encod = Encoding.Unicode;
public void ServerStartInThread() {
byte[] bytes = new Byte[1024];
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 5500);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket = socket;
try {
socket.Bind(localEndPoint);
socket.Listen(100);
Thread pollThread = new Thread(delegate () {
serverIsAlive = true; // needs if reopen
SendMessage("Server Started");
while (serverIsAlive) {
try {
SendMessage("Server is waiting for a connection...");
socket.BeginAccept(new AsyncCallback(ServerOnClientConnection), socket);
waitForConnection.Reset();
waitForConnection.WaitOne();
}
catch (Exception ex) {
SendMessage("Server: " + ex.ToString());
}
}
SendMessage("Server Stopped");
socket.Close();
}) {
Name = "SocketServer"
};
pollThread.Start();
}
catch (Exception ex) {
SendMessage("Server: " + ex.ToString());
}
}
public void ServerOnClientConnection(IAsyncResult ar) {
try {
Socket listener = (Socket)ar.AsyncState;
Socket clientSocket = listener.EndAccept(ar);
SendMessage("ServerOnClientConnection Client: " + clientSocket.RemoteEndPoint.ToString());
StateObject state = new StateObject() {
socket = clientSocket
};
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ServerReceiveCallback), state);
waitForConnection.Set();
}
catch (Exception ex) {
SendMessage("ServerOnClientConnection: " + ex.ToString());
}
}
public void ServerReceiveCallback(IAsyncResult ar) {
StateObject state = (StateObject)ar.AsyncState;
Socket socket = state.socket;
try {
if (socket == null) return;
if (!socket.Connected) {
return;
}
int bytesRead = socket.EndReceive(ar);
if (bytesRead > 0) {
state.sb.Append(encod.GetString(state.buffer, 0, bytesRead));
socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ServerReceiveCallback), state);
}
}
catch (Exception ex) {
SendMessage("ServerReceiveCallback: " + ex.ToString());
}
}
#endregion
#region client
private Socket client;
private bool isAlive = false;
private ManualResetEvent connectDone = new ManualResetEvent(false);
public void StartInThread() {
try {
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 5500);
Thread pollThread = new Thread(delegate () {
isAlive = true;
while (isAlive) {
try {
if (client != null && client.Connected) {
continue;
}
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(remoteEP, new AsyncCallback(ClientConnectCallback), client);
SendMessage(string.Format("Client {0} requests connection", client.LocalEndPoint.ToString()));
connectDone.Reset();
connectDone.WaitOne(3000, false);
if (client.Connected) {
StateObject state = new StateObject() {
socket = client
};
SendMessage(string.Format("Client {0} connected", client.LocalEndPoint.ToString()));
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ClientReceiveCallback), state);
}
}
catch (Exception ex) {
SendMessage("ClientStartInThread1: " + ex.ToString());
}
}
SendMessage("Client Disconnected");
}) {
Name = "ClientThread"
};
pollThread.Start();
}
catch (Exception ex) {
SendMessage("ClientStartInThread2: " + ex.ToString());
}
}
private void ClientConnectCallback(IAsyncResult ar) {
try {
Socket socket = (Socket)ar.AsyncState;
socket.EndConnect(ar);
connectDone.Set();
}
catch (Exception ex) {
SendMessage("ClientConnectCallback: " + ex.ToString());
}
}
private void ClientReceiveCallback(IAsyncResult ar) {
StateObject state = (StateObject)ar.AsyncState;
Socket socket = state.socket;
if (socket == null || !socket.Connected) return;
try {
int bytesRead = socket.EndReceive(ar);
if (bytesRead > 0) {
state.sb.Append(encod.GetString(state.buffer, 0, bytesRead));
socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ClientReceiveCallback), state);
}
else {
socket.Close();
}
}
catch (Exception ex) {
SendMessage("ClientReceiveCallback: " + ex.ToString());
socket.Close();
}
}
#endregion
private void SendMessage(string v) {
System.Diagnostics.Debug.WriteLine(v);
}
public static void Start() {
TestSockets server = new TestSockets();
server.ServerStartInThread();
TestSockets c1 = new TestSockets();
c1.StartInThread();
TestSockets c2 = new TestSockets();
c2.StartInThread();
TestSockets c3 = new TestSockets();
c3.StartInThread();
}
}
public class StateObject {
public Socket socket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}
}
You have a race condition in your code that results in the waitForConnection event handle being set twice, with the second call to Set() having no effect, before the main server thread has a chance to proceed past the BeginAccept() and reset the handle. This causes it to miss the second set.
One way to fix it would be to switch to a semaphore object. For example:
#region server
Socket serverSocket;
bool serverIsAlive;
SemaphoreSlim waitForConnection = new SemaphoreSlim(0);
private Encoding encod = Encoding.Unicode;
public void ServerStartInThread()
{
byte[] bytes = new Byte[1024];
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 5500);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket = socket;
try
{
socket.Bind(localEndPoint);
socket.Listen(100);
Thread pollThread = new Thread(delegate () {
serverIsAlive = true; // needs if reopen
SendMessage("Server Started");
while (serverIsAlive)
{
try
{
SendMessage("Server is waiting for a connection...");
socket.BeginAccept(new AsyncCallback(ServerOnClientConnection), socket);
waitForConnection.Wait();
}
catch (Exception ex)
{
SendMessage("Server: " + ex.ToString());
}
}
SendMessage("Server Stopped");
socket.Close();
})
{
Name = "SocketServer"
};
pollThread.Start();
}
catch (Exception ex)
{
SendMessage("Server: " + ex.ToString());
}
}
public void ServerOnClientConnection(IAsyncResult ar)
{
try
{
Socket listener = (Socket)ar.AsyncState;
Socket clientSocket = listener.EndAccept(ar);
SendMessage("ServerOnClientConnection Client: " + clientSocket.RemoteEndPoint.ToString());
StateObject state = new StateObject()
{
socket = clientSocket
};
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ServerReceiveCallback), state);
waitForConnection.Release();
}
catch (Exception ex)
{
SendMessage("ServerOnClientConnection: " + ex.ToString());
}
}
This will allow the ServerOnClientConnection() method to increment the semaphore count, so that the main server thread can continue to loop until all of the accepted connections have been observed.
However, frankly, the MSDN examples that use these event handles (which is what I'm assuming your code is based on, either directly or indirectly) are IMHO simply broken. They introduce thread synchronization complexities where none is actually needed, unnecessarily complicating the code and making it harder to get the code to work correctly.
A more idiomatic approach would be to not have the extra thread at all, call BeginAccept() once in the ServerStartInThread() method (which you'd probably rename to just ServerStart()) and call BeginAccept() in the ServerOnClientConnection() method after handling the currently accepted client. I.e. just like you handle the BeginReceive() now.
That said, IMHO even the idiomatic approach is outdated. It worked very well when the API was first designed, but .NET has come a long way since then and has much better mechanisms for dealing with asynchronous operations like this. I posted in this answer an example of a simple chat server that shows how you can use async/await to implement this sort of thing in a much simpler, easier-to-read way. You may want to look at that for ideas on how to apply the same techniques to your own code.
So I am writing a simple client-server application. It should send a packet, then wait to receive a packet, than send one etc... The problem is, it recieves the first packet, but when I start the TcpListener in the second iteration, it gives me this error:
No connection could be made because the target machine actively
refused it 127.0.0.1:13
private void listenForConnections()
{
bool prejelPaket = false;
listener = new TcpListener(IPAddress, port);
listener.Start();
while (!packetReceived)
{
try
{
client = listener.AcceptTcpClient();
listener.Stop();
networkStream = client.GetStream();
byte[] message = new byte[1024];
networkStream.Read(message, 0, message.Length);
networkStream.Close();
string strMessage = Encoding.UTF8.GetString(message);
packetReceived= true;
MessageBox.Show("received message: " + strMessage);
client.Close();
}
catch (Exception ee)
{
thListen.Join();
}
}
}
private void sendPacket(object pClient)
{
string message = "test message;
try
{
client = (TcpClient)pClient;
client.Connect(IPAddress, port);
networkStream = client.GetStream();
byte[] strMessage = Encoding.UTF8.GetBytes(message);
networkStream.Write(strMessage, 0, strMessage.Length);
networkStream.Close();
client.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
Create the client / networkstream once. Store them in a property until you are finished sending and receiving. Then close and dispose. Do not stop / close the connection between each iteration.
Move the
listener.Stop();
outside the while loop.
EDIT: to explain why
The reason why it works the first time but second iteration fails is because after the first client is accepted from client = listener.AcceptTcpClient() the next line of code calls listener.Stop() which stops listening for connections. Any subsequent calls to listener.AcceptTcpClient() will throw an InvalidOperationException. Moving listener.Stop() outside the while loop only stops listening for connections once it exits the loop.
Looking at it again packetReceived is set to true in the first iteration as well, so it's going to exit the while loop after the first client anyway, is this the intended behaviour?
I used to write socket programs in C and can't understand why the above is happening.
My server blocks at a Receive call, when it returns 0, I break out of the while loop and shutdown the thread.
public class MyServer {
public MyServer() {
}
public void Init() {
ThreadPool.QueueUserWorkItem(StartListening);
while (true) {
Console.Read();
}
}
public void StartListening(Object state) {
// Establish the local endpoint for the socket.
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try {
// Bind the socket to the local endpoint and listen for incoming connections.
listener.Bind(localEndPoint);
listener.Listen(100);
while (true) {
Console.WriteLine("Waiting for a connection...");
// get connection
Socket client = listener.Accept();
// push client to another thread
ThreadPool.QueueUserWorkItem(HandleClient, client);
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
private void HandleClient(Object obj) {
// Get the socket that handles the client request.
Socket client = (Socket)obj;
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
try {
while (true) {
int bytesRead = client.Receive(state.buffer);
Console.WriteLine("bytesRead=" + bytesRead);
// remote dc.
if (bytesRead == 0)
break;
String content = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", content.Length, content);
client.Send(state.buffer, 0, state.buffer.Length, 0);
}
} catch (SocketException e) {
Console.WriteLine("SocketException : {0}", e.ToString());
}
client.Shutdown(SocketShutdown.Both);
client.Close();
}
private void Send(Socket handler, String data) {
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
//handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
}
}
However, when I click on the close button ("x") of the client, server's Receive call throws a SocketException. According to MSDN's Remarks section, this shouldn't happen because I've satisfied both the connection-oriented part (see above) and client shutdown part(see below) conditions.
Client.cs (pseudo):
public class MyClient {
public void Init() {
byte[] bytes = new byte[1024];
Socket sender = null;
try {
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);
sender = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
while (true) {
// Encode the data string into a byte array.
String input = Console.ReadLine();
byte[] msg = Encoding.ASCII.GetBytes(input);
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
Console.WriteLine("Echoed test = {0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
}
} catch (ArgumentNullException ane) {
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
} catch (SocketException se) {
Console.WriteLine("SocketException : {0}", se.ToString());
} catch (Exception e) {
Console.WriteLine("Unexpected exception : {0}", e.ToString());
} finally {
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
}
}
My shallow understanding of finally blocks is that it will always execute. But it doesn't seem to be the case here.
SO, what did I do wrong here? Should I just catch the exception, close the client socket on the server side and just move on, ignoring it? But I would prefer if an exception were not thrown at all.
I'm working with a windows form application in C#. I'm using a socket client which is connecting in an asynchronous way to a server.
I would like the socket to try reconnecting immediately to the server if the connection is broken for any reason.
My receive routine looks like this
public void StartReceiving()
{
StateObject state = new StateObject();
state.workSocket = this.socketClient;
socketClient.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(OnDataReceived), state);
}
private void OnDataReceived(IAsyncResult ar)
{
try
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int iReadBytes = client.EndReceive(ar);
if (iReadBytes > 0)
{
byte[] bytesReceived = new byte[iReadBytes];
Buffer.BlockCopy(state.buffer, 0, bytesReceived, 0, iReadBytes);
this.responseList.Enqueue(bytesReceived);
StartReceiving();
receiveDone.Set();
}
else
{
NotifyClientStatusSubscribers(false);
}
}
catch (Exception e)
{
}
}
When NotifyClientStatusSubscribers(false) is called the function StopClient is executed:
public void StopClient()
{
this.canRun = false;
this.socketClient.Shutdown(SocketShutdown.Both);
socketClient.BeginDisconnect(true, new AsyncCallback(DisconnectCallback), this.socketClient);
}
private void DisconnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the disconnection.
client.EndDisconnect(ar);
this.socketClient.Close();
this.socketClient = null;
}
catch (Exception e)
{
}
}
Now I try reconnecting by calling the following functions:
public void StartClient()
{
this.canRun = true;
this.MessageProcessingThread = new Thread(this.MessageProcessingThreadStart);
this.MessageProcessingThread.Start();
this.socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this.socketClient.LingerState.Enabled = false;
}
public void StartConnecting()
{
socketClient.BeginConnect(this.remoteEP, new AsyncCallback(ConnectCallback), this.socketClient);
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
// Signal that the connection has been made.
connectDone.Set();
StartReceiving();
NotifyClientStatusSubscribers(true);
}
catch(Exception e)
{
StartConnecting();
}
}
The socket reconnects when the connection is available, but after a couple of seconds I get the following unhandled exception:
"A connection request was made on an already connected socket."
How is this possible?
It's possible if you get an exception in ConnectCallback and you've actually connected successfully. Set a break point in the catch statement of the ConnectCallback and see if there is an exception that gets raised there- currently there is nothing that will tell you that you got an exception.
Recently I have tackled a strange behaviour of .Net synchronous receive method. I needed to write an application that has nodes which communicate with each other by sending/receiving data. Each server has a receipt loop which is synchronous, after receiving a serialized class it deserializes and processes it. After that it sends asynchronously this serialized class to some chosen nodes (using AsynchSendTo).
The MSDN clearly says that:
"If you are using a connection-oriented Socket, the Receive method
will read as much data as is available, up to the size of the buffer.
If the remote host shuts down the Socket connection with the Shutdown
method, and all available data has been received, the Receive method
will complete immediately and return zero bytes."
In my case it's not true. There are some random cases when the Receive doesn't block and returns 0 bytes (non-deterministic situtation) right away after establishing connection. I'm 100% sure that the sender was sending at lest 1000 bytes. One more funny fact: when putting Sleep(500) before receive everything works just fine. Hereunder is the receiving code:
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
_listener.Bind(_serverEndpoint);
_listener.Listen(Int32.MaxValue);
while (true)
{
Console.WriteLine("Waiting for connection...");
Socket handler = _listener.Accept();
int totalBytes = 0;
int bytesRec;
var bytes = new byte[DATAGRAM_BUFFER];
do
{
//Thread.Sleep(500);
bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None);
totalBytes += bytesRec;
} while (bytesRec > 0);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
catch (SocketException e)
{
Console.WriteLine(e);
}
Also the sending part:
public void AsynchSendTo(Datagram datagram, IPEndPoint recipient)
{
byte[] byteDatagram = SerializeDatagram(datagram);
try
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect(recipient, ConnectCallback, new StateObject(byteDatagram, byteDatagram.Length, socket));
}
catch (SocketException e)
{
Console.WriteLine(e);
}
}
public void ConnectCallback(IAsyncResult result)
{
try
{
var stateObject = (StateObject)result.AsyncState;
var socket = stateObject.Socket;
socket.EndConnect(result);
socket.BeginSend(stateObject.Data, 0, stateObject.Data.Length, 0, new AsyncCallback(SendCallback), socket);
}
catch (Exception ex)
{
Console.WriteLine("catched!" + ex.ToString());
}
}
public void SendCallback(IAsyncResult result)
{
try
{
var client = (Socket)result.AsyncState;
client.EndSend(result);
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
class StateObject
{
public Byte[] Data { get; set; }
public int Size;
public Socket Socket;
}
My question: am I using the synchronous receive in a wrong way? Why it doesn't block event though there is data to receive?
You're shooting yourself in the foot.
bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None);
At the very beginning of the connection, Available will be 0, forcing it to return immediately with 0. Instead, you should specify the number of bytes which are free in your buffer (e.g. bytes.Length-totalBytes), then it will also block.
You may have a concurrency problem here. After you accept a connection, you jump straight into receive. The sender process may not have enough time to reach the call to send and so your handler.Available is 0 and the receive returns.
This is also why the "bug" does not occur when you add the sleep of 500 ms.