C# Check if socket is disconnected? - c#

How can you check if a non-blocking socket is disconnect without using Poll?

Create a cusomt socket class inheriting .net socket class :
public delegate void SocketEventHandler(Socket socket);
public class CustomSocket : Socket
{
private readonly Timer timer;
private const int INTERVAL = 1000;
public CustomSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
: base(addressFamily, socketType, protocolType)
{
timer = new Timer { Interval = INTERVAL };
timer.Tick += TimerTick;
}
public CustomSocket(SocketInformation socketInformation)
: base(socketInformation)
{
timer = new Timer { Interval = INTERVAL };
timer.Tick += TimerTick;
}
private readonly List<SocketEventHandler> onCloseHandlers = new List<SocketEventHandler>();
public event SocketEventHandler SocketClosed
{
add { onCloseHandlers.Add(value); }
remove { onCloseHandlers.Remove(value); }
}
public bool EventsEnabled
{
set
{
if(value)
timer.Start();
else
timer.Stop();
}
}
private void TimerTick(object sender, EventArgs e)
{
if (!Connected)
{
foreach (var socketEventHandler in onCloseHandlers)
socketEventHandler.Invoke(this);
EventsEnabled = false;
}
}
// Hiding base connected property
public new bool Connected
{
get
{
bool part1 = Poll(1000, SelectMode.SelectRead);
bool part2 = (Available == 0);
if (part1 & part2)
return false;
else
return true;
}
}
}
Then use it like this :
var socket = new CustomSocket(
//parameters
);
socket.SocketClosed += socket_SocketClosed;
socket.EventsEnabled = true;
void socket_SocketClosed(Socket socket)
{
// do what you want
}
I have just implemented a Socket close event in each socket. so your application should register event handlers for this event. then socket will inform your application if it was closed itself ;)
if there was any problem with code, inform me.

The Socket class has a Connected property. According to MSDN the call to check is non-blocking. Is this not what you're looking for?

Related

Stop Timer in another class

I have a program that sends and receives messages over serial.
I have this Sender class:
public class Sender
{
private System.Timers.Timer _responseTimer;
public Sender(SerialPort sp)
{
_serialPort = sp;
_responseTimer = new System.Timers.Timer(2000);
}
public void Attach(ISenderObserver iso)
{
_responseTimer.Elapsed += new ElapsedEventHandler(iso.ResponseTooSlowEvent);
}
public void SendCommand(String command)
{
//start response timeout timer
_responseTimer.AutoReset = false;
_responseTimer.Enabled = true;
_serialPort.Write(command);
}
}
And then I have this receiving class:
public class Receiver : ISenderObserver
{
private static bool _continue;
private static SerialPort _serialPort;
private Thread _receiveThread;
public Receiver(SerialPort sp)
{
_serialPort = sp;
_continue = true;
_serialPort.Open();
//Start the receiving thread
_receiveThread = new Thread(Receive);
_receiveThread.Start();
}
public void Receive()
{
while (_continue)
{
String receivedMessage = _serialPort.ReadLine();
//parse received message
}
}
public void ResponseTooSlowEvent(object source, System.Timers.ElapsedEventArgs e)
{
Console.Write("\nToo Slow!");
}
}
And this interface:
public interface ISenderObserver
{
void ResponseTooSlowEvent(object source, ElapsedEventArgs e);
}
They are called like this in their main controller:
sender = new Sender(_serialPort);
receiver = new Receiver(_serialPort);
sender.Attach(receiver);
The reason for the timer is that I want the program to abort its waiting for a certain message if it takes too long, thereby avoiding a deadlock if it gets disconnected.
I thereby want to stop the timer within the Receiver-class as soon as line:
String receivedMessage = _serialPort.ReadLine();
is finished.
How can I do this without having dependencies all over the place?

Adding Events to .NET Sockets in C#

I have a CustomSocket class that extends the Socket that adds events to get some feedback about clients disconnecting from a server. I am wondering how to add my client disconnect method to the event delegate if the _listenerSocket.Accept() method returns a Socket and not my CustomSocket class which has the events in it?? The code is as below.
public class CustomSocket : Socket
{
private readonly Timer timer;
private const int INTERVAL = 1000;
public delegate void SocketEventHandler(Socket socket);
public CustomSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) : base(addressFamily, socketType, protocolType)
{
timer = new Timer { Interval = INTERVAL };
timer.Elapsed += TimerTick;
}
public CustomSocket(SocketInformation socketInformation) : base(socketInformation)
{
timer = new Timer { Interval = INTERVAL };
timer.Elapsed += TimerTick;
}
private readonly List<SocketEventHandler> onCloseHandlers = new List<SocketEventHandler>();
public event SocketEventHandler SocketClosed
{
add { onCloseHandlers.Add(value); }
remove { onCloseHandlers.Remove(value); }
}
public bool EventsEnabled
{
set
{
if (value)
timer.Start();
else
timer.Stop();
}
}
private void TimerTick(object sender, EventArgs e)
{
if (!Connected)
{
foreach (var socketEventHandler in onCloseHandlers)
socketEventHandler.Invoke(this);
EventsEnabled = false;
}
}
// Hiding base connected property
public new bool Connected
{
get
{
bool part1 = Poll(1000, SelectMode.SelectRead);
bool part2 = (Available == 0);
if (part1 & part2)
return false;
else
return true;
}
}
}
I was thinking that I would want to add for events on the Socket that is returned from the Socket.Accept(); method except that this is a Socket is not a CustomSocket so there there are no events. I think I going about this the wrong way.
static void ListenThread()
{
try
{
for (; ; )
{
_listenerSocket.Listen(5);
_clients.Add(new ClientData(_listenerSocket.Accept()));
}
}
catch
{
//
}
}
I tried this
static void ListenThread()
{
try
{
for (; ; )
{
_listenerSocket.Listen(5);
CustomSocket cs = (CustomSocket) _listenerSocket.Accept();
_clients.Add(new ClientData(cs));
cs.SocketClosed += CsOnSocketClosed;
}
}
catch
{
//
}
}
But I get casting errors etc..
Any help would be appreciated..
Matt
You can't cast a Socket to a CustomSocket. Because Accept returns a Socket and not a CustomSocket.
You could wrap a Socket in a CustomSocket which takes a Socket as parameter like this to solve your issue.
class CustomSocket
{
private Socket _socket;
public Socket Socket
{
get
{
return _socket;
}
}
public CustomSocket(Socket s)
{
_socket = s;
}
}
You definitely need to use composition instead of inheritance for this, due to the fact that the Accept() method will never return an instance of your own class. See existing socket wrappers like TcpClient, NetworkStream, etc. for inspiration. There's not enough detail here to be able to provide specific guidance as to how to compose your Socket instance. However, for dealing with the Accept() method scenario specifically, it would look something like this:
class CustomSocket
{
private Socket _socket;
public CustomSocket(Socket socket)
{
_socket = socket;
}
public CustomSocket Accept()
{
return new CustomSocket(_socket.Accept());
}
}
Finally, it's not entirely clear what the overall goal in sub-classing/wrapping the Socket class here is, but the code you posted so far looks like you are trying to abstract a polling mechanism on the Socket class.
But polling a Socket is the least efficient way to use it, and is unnecessary. You may find that by using the asynchronous model with the Socket (e.g. Socket.BeginAccept(), ...BeginRead(), etc.) that you don't need to abstract anything, and that you can use the Socket class directly.

"Delegate to an instance method cannot have null 'this' " while forwarding an event

Im trying to forward an event OnClientMessage from my class Client over the class Server to outside my libary.
Client.cs
public class Client
{
private TcpClient tcpClient;
private StreamWriter writer;
private Boolean alive = true;
private int id;
public delegate void OnClientMessageHandler(Client sender, String message);
public delegate void OnClientDisconnectHandler(Client sender);
public event OnClientMessageHandler OnClientMessage;
public event OnClientDisconnectHandler OnClientDisconnect;
public Client(TcpClient tcpClient, int id)
{
this.tcpClient = tcpClient;
this.id = id;
writer = new StreamWriter(tcpClient.GetStream());
new Thread(() =>
{
Listen(new StreamReader(tcpClient.GetStream()));
}).Start();
}
void Listen(StreamReader reader)
{
while (tcpClient.GetStream().DataAvailable && alive)
{
OnClientMessage(this, reader.ReadLine());
Thread.Sleep(150);
}
}
public void Write(String message)
{
writer.WriteLine(message);
writer.Flush();
}
public int GetID()
{
return id;
}
public void Close()
{
alive = false;
writer.Close();
tcpClient.Close();
OnClientDisconnect(this);
}
}
Server.cs
public class Server
{
private IPAddress serverIP;
private short serverPort;
private TcpListener serverListener;
private int serverClientCount;
public List<Client> serverClients = new List<Client>();
private Boolean running;
public delegate void OnClientMessageHandler(Client sender, String message);
public delegate void OnClientDisconnectHandler(Client sender);
public event OnClientMessageHandler OnClientMessage;
public event OnClientDisconnectHandler OnClientDisconnect;
public Server(IPAddress ip, short port, Boolean autoStart = true)
{
this.serverIP = ip;
this.serverPort = port;
if(autoStart)
OpenServer();
}
public void OpenServer()
{
serverListener = new TcpListener(serverIP, serverPort);
serverListener.Start();
running = true;
while (running)
{
if (serverListener.Pending())
{
TcpClient tcpClient = serverListener.AcceptTcpClient();
new Thread(() =>
{
Client client;
client = new Client(tcpClient, serverClientCount);
client.OnClientMessage += new Client.OnClientMessageHandler(OnClientMessage);
client.OnClientDisconnect += new Client.OnClientDisconnectHandler(OnClientDisconnect);
serverClients.Add(client);
serverClientCount++;
}).Start();
}
else
{
Thread.Sleep(150);
}
}
}
public void WriteToClient(Client client, String message)
{
client.Write(message);
}
public void WriteToAll(String message)
{
serverClients.ForEach(client => client.Write(message));
}
public void Shutdown()
{
running = false;
serverClients.ForEach(client => client.Close());
serverListener.Stop();
}
}
Now when the event is firing the application crashes with Delegate to an instance method cannot have null 'this'.
Are I'm doing something wrong or isn't this the right way to forward an event?
This is pretty unique, never once seen anybody do this. It is a regression in the .NET Framework, 3.5 gives you a much better exception. Basic problem is that you made the event subscribe itself. A simple version to repro that crash:
using System;
class Program {
public static event Action Kaboom;
static void Main(string[] args) {
Kaboom += new Action(Kaboom); // 3.5 raises an exception here
var handler = Kaboom;
if (handler != null) handler(); // kaboom
}
}
You are not actually "forwarding" the event. Untangle your names and code. Add, say, a Fire() method.

"Unconnected" async socket prevents application shutdown

I wrote a small c# class to check for TCP connectivity (connection to TCP socket succeeds), using BeginConnect(). It appears to work well, IF the endpoint in question is available and the TCP session is actually connected.
However, when the endpoint is not listening and the connection times out, something weird happens: The class keeps "hanging" for about 15 to 20 seconds. Which coincides with the default timeout value.
However, I call socket.Close() when the timeout triggers - Which is said by MSDN to cancel all async operations.
Why does the class prevent the application from shutting down, when the connection does not succeed? What am I doing wrong?
public class CheckTCP
{
#region "Member Variables"
// socket connect timeout value
private int _timeout = 2000;
// check complete event
public event EventHandler<CheckCompletedEventArgs> CheckCompleted;
// perform TCP connect check
public void PerformCheck(EndPoint Socket)
{
StateObject state = new StateObject();
state.Me = this;
state.WorkSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
state.TimeoutTimer = new Timer();
state.TimeoutTimer.Interval = _timeout;
state.TimeoutTimer.Elapsed += (sender, e) => timeout_elapsed(sender, e, state);
state.TimeoutTimer.Start();
state.WorkSocket.SendTimeout = _timeout;
state.WorkSocket.ReceiveTimeout = _timeout;
state.WorkSocket.BeginConnect(Socket, new AsyncCallback(ConnectCallback), state);
}
// connection callback
private static void ConnectCallback(IAsyncResult ar)
{
StateObject state = (StateObject) ar.AsyncState;
state.TimeoutTimer.Stop();
state.TimeoutTimer.Dispose();
CheckCompletedEventArgs ea = new CheckCompletedEventArgs();
if (state.WorkSocket.Connected)
{
state.WorkSocket.EndConnect(ar);
state.WorkSocket.Close();
ea.Success = true;
state.Me.OnCheckCompleted(ea);
}
else
{
ea.Success = false;
state.Me.OnCheckCompleted(ea);
}
state.WorkSocket.Dispose();
state.Me = null;
}
// timeout callback
private void timeout_elapsed(object sender, EventArgs e, StateObject state)
{
state.TimeoutTimer.Stop();
state.WorkSocket.Close();
}
#endregion
// raiseevent helper
protected virtual void OnCheckCompleted(CheckCompletedEventArgs e)
{
// raise the event
EventHandler<CheckCompletedEventArgs> handler = CheckCompleted;
if (handler != null)
{
handler(this, e);
}
}
// checkcompleted event args class
public class CheckCompletedEventArgs : EventArgs
{
public bool Success { set; get; }
}
// async state object
public class StateObject
{
public EndPoint EndpointSocket { set; get; }
public Socket WorkSocket { set; get; }
public Timer TimeoutTimer { set; get; }
public CheckTCP Me { set; get; }
}
}

Wait for event from SqlListener

I have implemented a SqlListener class that uses SqlDependency to wait for changes in SQL database. At one point in my business workflow I need to wait for a record turning up in the database. The SqlListener triggers an event when requested record is found. This works fine. I can make it work by entering a While-loop and wait until I detect the event being returned. But this is not ideal design. It makes the processor spin a lot in vain.
I would like to wait for the event in a more intelligent manner. I read a lot of suggestions on using Task, NotificationDelegate, ManualResetEvent, etc. .... but I was not able to get it all together.
A simplified example will probably make it easier to understand. This is my current setup that works. But if possible I would like to get rid of the ugly while loop.
private const int MaxWaitTime = 5;
private SqlListener<RecordType> _recordListener;
private RecordType _record;
/// <summary>
/// Request a record and wait until it is found.
/// </summary>
public RecordType GetRecordAwait(int requestedId)
{
// Initiate listening for record
_recordListener = new SqlListener<RecordType>();
_recordListener.SqlModified += SqlListener_SqlModified;
_recordListener.StartListening(requestedId);
// Wait until record is found
var startTime = DateTime.Now;
while (_record == null &&
DateTime.Now.Subtract(startTime).TotalSeconds < MaxWaitTime)
{
Thread.Sleep(1);
}
// Stop listening
_recordListener.SqlModified -= SqlListener_SqlModified;
_recordListener.Dispose();
_recordListener = null;
// Return record
return _record;
}
private void SqlListener_SqlModified(object sender, SqlModifiedArgs args)
{
_record = (RecordType)args.Record;
}
Instead of using While, you could go with Timer and events. Something like:
public class ListenerWaiting
{
public ListenerWaiting(int waitingTimeSeconds)
{
_waitSeconds = waitingTimeSeconds;
}
private int _waitSeconds;
private System.Timers.Timer _timer;
private Listener _listener;
public event EventHandler<string> ListenerDone;
public void Listen(int listeningPeriodSeconds)
{
_listener = new Listener(listeningPeriodSeconds * 1000);
_listener.ListenerCompleted += ListenerListenerCompleted;
_timer = new System.Timers.Timer(_waitSeconds * 1000) {Enabled = true};
_timer.Elapsed += TimerElapsed;
}
void ListenerListenerCompleted(object sender, string e)
{
StopTimer();
StopListener();
if (ListenerDone != null)
ListenerDone(this, "Waiting success! Message was: " + e);
}
void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
StopTimer();
StopListener();
if (ListenerDone != null)
ListenerDone(this, "Waited longer than set, aborted waiting...");
}
private void StopTimer()
{
_timer.Stop();
_timer.Elapsed -= TimerElapsed;
_timer = null;
}
private void StopListener()
{
_listener.ListenerCompleted -= ListenerListenerCompleted;
_listener = null;
}
}
public class Listener
{
private System.Timers.Timer _timer;
private string _listeningPeriodSeconds;
public event EventHandler<string> ListenerCompleted;
public Listener(int listeningPeriodSeconds)
{
_listeningPeriodSeconds = listeningPeriodSeconds.ToString();
_timer = new System.Timers.Timer(listeningPeriodSeconds) { Enabled = true };
_timer.Elapsed += TimerElapsed;
}
private void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
_timer.Elapsed -= TimerElapsed;
_timer = null;
if (ListenerCompleted != null)
ListenerCompleted(this, _listeningPeriodSeconds);
}
}
...and then consume it with:
static void Main(string[] args)
{
var wait = new ListenerWaiting(5);
wait.ListenerDone += WaitListenerDone;
wait.Listen(3);
Console.ReadLine();
}
static void WaitListenerDone(object sender, string e)
{
Console.WriteLine(e);
}
I guess I could find better names for classes, but you'll get the idea ;)
In fact the solution was more simple than I first thought. When I rephrased my question and searched again I found it. The ManualResetEvent as mentioned already in my question turned out to be the simplest way to solve it.
All I had to do was to add a ManualResetEvent and set it to wait ;-)
private const int MaxWaitTime = 5000;
private SqlListener<RecordType> _recordListener;
private RecordType _record;
private readonly ManualResetEvent _recordWaiter = new ManualResetEvent(false);
/// <summary>
/// Request a record and wait until it is found.
/// </summary>
public RecordType GetRecordAwait(int requestedId)
{
// Initiate listening for record
_recordListener = new SqlListener<RecordType>();
_recordListener.SqlModified += SqlListener_SqlModified;
_recordListener.StartListening(requestedId);
// Wait synchronously until record is found
_recordWaiter.WaitOne(MaxWaitTime);
// Stop listening
_recordListener.SqlModified -= SqlListener_SqlModified;
_recordListener.Dispose();
_recordListener = null;
// Return record
return _record;
}
private void SqlListener_SqlModified(object sender, SqlModifiedArgs args)
{
_record = (RecordType)args.Record;
_recordWaiter.Set();
}

Categories

Resources