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; }
}
}
Related
I made an "Acceptor" class which in the cunstroctor it accepts an amount of TcpListeners. Starting from port 8484 and above.
class Acceptor
{
private List<TcpListener> Listeners;
private static int clientCount = 0;
private static int portStart = 8484;
public Acceptor(int capacity)
{
Listeners = new List<TcpListener>(capacity);
for (int i = 0; i < capacity; i++)
{
Listeners.Add(new TcpListener(IPAddress.Any, portStart));
portStart++;
}
foreach (TcpListener listener in Listeners)
{
try
{
listener.Start();
listener.BeginAcceptSocket(new AsyncCallback(EndAccept), null);
}
catch (SocketException ex)
{
Debug.WriteLine("Failed to start TcpListener, Error {0}.", ex.Message);
}
}
Debug.WriteLine(string.Format("Initiated {0} Listeners from 8484 - {1}.", capacity, portStart));
}
public void EndAccept(IAsyncResult IAR)
{
TcpListener Listener = (TcpListener)IAR.AsyncState;
Socket socket = Listener.EndAcceptSocket(IAR);
frmMain.Clients.Add(clientCount, new Client(socket));
Listener.Stop();
Listener = null;
clientCount++;
frmMain.Instance.UpdateClients();
}
}
However, that doesn't work. The program crashes when accepting a new connection, why's that?
You're passing null as the "state" in BeginAcceptSocket, thus the error when you attempt to cast it back and then use it.
Try changing this line:
listener.BeginAcceptSocket(new AsyncCallback(EndAccept), null);
To:
listener.BeginAcceptSocket(new AsyncCallback(EndAccept), listener);
This is how i implement a Listener:
public class EasySocketListener : IDisposable
{
private Socket _socket;
public void Start(int port)
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.Bind(new IPEndPoint(IPAddress.Any, port));
_socket.Listen(1);
StartAccepting();
}
private void StartAccepting()
{
try
{
_socket.BeginAccept((asyncResult) =>
{
try
{
Socket clientSocket = _socket.EndAccept(asyncResult);
if (OnSocketAccept != null)
OnSocketAccept(this, new SocketEventArgs(clientSocket));
StartAccepting();
}
catch { }
}, null);
}
catch { }
}
public void Dispose()
{
if (_socket != null)
{
_socket.Dispose();
_socket = null;
}
}
public event EventHandler<SocketEventArgs> OnSocketAccept;
}
This can accept multiple client sockets. When a client connects, the OnSocketAccept triggers.
Needs the SocketEventArgs:
public class SocketEventArgs : EventArgs
{
public Socket Socket { get; private set; }
public SocketEventArgs(Socket socket)
{
Socket = socket;
}
}
example:
private void Init()
{
_listener = new EasySocketListener();
_listener.OnSocketAccept += Listener_OnSocketAccept;
_listener.Start(port);
}
private void Listener_OnSocketAccept(object sender, SocketEventArgs e)
{
Debug.WriteLine( e.Socket.RemoteEndPoint );
}
This will come on my blog http://csharp.vanlangen.biz but haven't wrote it there yet. You can find some methods for reading asynchronous from a socket.
I am writing a TCP based client that need to send and receive data. I have used the Asynchronous Programming Model (APM) provided for Socket class by the .NET Framework.
After being connected to the socket, I start wait for data on the socket using BeginReceive.
Now, while I am waiting for the data on the Socket, I may need to send data over the socket. And the send method can be called multiple times,
So i have make sure that
All the bytes from previous Send call is entirely sent.
The way i am sending the Data is safe considering that, while a data send is in progress, any call to send data can be made.
This is my first work on socket, So is my approach right to send data ?
private readonly object writeLock = new object();
public void Send(NetworkCommand cmd)
{
var data = cmd.ToBytesWithLengthPrefix();
ThreadPool.QueueUserWorkItem(AsyncDataSent, data);
}
private int bytesSent;
private void AsyncDataSent(object odata)
{
lock (writeLock)
{
var data = (byte[])odata;
int total = data.Length;
bytesSent = 0;
int buf = Globals.BUFFER_SIZE;
while (bytesSent < total)
{
if (total - bytesSent < Globals.BUFFER_SIZE)
{
buf = total - bytesSent;
}
IAsyncResult ar = socket.BeginSend(data, bytesSent, buf, SocketFlags.None, DataSentCallback, data);
ar.AsyncWaitHandle.WaitOne();
}
}
}
How object is changed into byte[], sometimes the NetworkCommand can be as big as 0.5 MB
public byte[] ToBytesWithLengthPrefix()
{
var stream = new MemoryStream();
try
{
Serializer.SerializeWithLengthPrefix(stream, this, PrefixStyle.Fixed32);
return stream.ToArray();
}
finally
{
stream.Close();
stream.Dispose();
}
}
Complete class
namespace Cybotech.Network
{
public delegate void ConnectedDelegate(IPEndPoint ep);
public delegate void DisconnectedDelegate(IPEndPoint ep);
public delegate void CommandReceivedDelagate(IPEndPoint ep, NetworkCommand cmd);
}
using System;
using System.Net;
using System.Net.Sockets;
using Cybotech.Helper;
using Cybotech.IO;
namespace Cybotech.Network
{
public class ClientState : IDisposable
{
private int _id;
private int _port;
private IPAddress _ip;
private IPEndPoint _endPoint;
private Socket _socket;
private ForwardStream _stream;
private byte[] _buffer;
public ClientState(IPEndPoint endPoint, Socket socket)
{
Init(endPoint, socket);
}
private void Init(IPEndPoint endPoint, Socket socket)
{
_endPoint = endPoint;
_ip = _endPoint.Address;
_port = _endPoint.Port;
_id = endPoint.GetHashCode();
_socket = socket;
_stream = new ForwardStream();
_buffer = new byte[Globals.BUFFER_SIZE];
}
public int Id
{
get { return _id; }
}
public int Port
{
get { return _port; }
}
public IPAddress Ip
{
get { return _ip; }
}
public IPEndPoint EndPoint
{
get { return _endPoint; }
}
public Socket Socket
{
get { return _socket; }
}
public ForwardStream Stream
{
get { return _stream; }
}
public byte[] Buffer
{
get { return _buffer; }
set { _buffer = value; }
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_stream != null)
{
_stream.Close();
_stream.Dispose();
}
if (_socket != null)
{
_socket.Close();
}
}
}
public void Dispose()
{
Dispose(true);
}
}
}
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using Cybotech.Command;
using Cybotech.Network;
namespace ExamServer.Network
{
public class TcpServer : IDisposable
{
private Socket socket;
private bool secure;
private readonly Dictionary<IPEndPoint, ClientState> clients = new Dictionary<IPEndPoint, ClientState>();
//public events
#region Events
public event CommandDelegate CommandReceived;
public event ConnectedDelegate ClientAdded;
public event DisconnectedDelegate ClientRemoved;
#endregion
//event invokers
#region Event Invoke methods
protected virtual void OnCommandReceived(IPEndPoint ep, NetworkCommand command)
{
CommandDelegate handler = CommandReceived;
if (handler != null) handler(ep, command);
}
protected virtual void OnClientAdded(IPEndPoint ep)
{
ConnectedDelegate handler = ClientAdded;
if (handler != null) handler(ep);
}
protected virtual void OnClientDisconnect(IPEndPoint ep)
{
DisconnectedDelegate handler = ClientRemoved;
if (handler != null) handler(ep);
}
#endregion
//public property
public string CertificatePath { get; set; }
public TcpServer(EndPoint endPoint, bool secure)
{
StartServer(endPoint, secure);
}
public TcpServer(IPAddress ip, int port, bool secure)
{
StartServer(new IPEndPoint(ip, port), secure);
}
public TcpServer(string host, int port, bool secure)
{
StartServer(new IPEndPoint(IPAddress.Parse(host), port), secure);
}
private void StartServer(EndPoint ep, bool ssl)
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(ep);
socket.Listen(150);
this.secure = ssl;
socket.BeginAccept(AcceptClientCallback, null);
}
private void AcceptClientCallback(IAsyncResult ar)
{
Socket client = socket.EndAccept(ar);
var ep = (IPEndPoint) client.RemoteEndPoint;
var state = new ClientState(ep, client);
if (secure)
{
//TODO : handle client for ssl authentication
}
//add client to
clients.Add(ep, state);
OnClientAdded(ep);
client.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ReceiveDataCallback, state);
//var thread = new Thread(ReceiveDataCallback);
//thread.Start(state);
}
private void ReceiveDataCallback(IAsyncResult ar)
{
ClientState state = (ClientState)ar.AsyncState;
try
{
var bytesRead = state.Socket.EndReceive(ar);
state.Stream.Write(state.Buffer, 0, bytesRead);
// check available commands
while (state.Stream.LengthPrefix > 0)
{
NetworkCommand cmd = NetworkCommand.CreateFromStream(state.Stream);
OnCommandReceived(state.EndPoint, cmd);
}
//start reading data again
state.Socket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ReceiveDataCallback, state);
}
catch (SocketException ex)
{
if (ex.NativeErrorCode.Equals(10054))
{
RemoveClient(state.EndPoint);
}
}
}
private void RemoveClient(IPEndPoint ep)
{
OnClientDisconnect(ep);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
//TODO : dispose all the client related socket stuff
}
}
public void Dispose()
{
Dispose(true);
}
}
}
The same client won't be able to send data to you unless he finishes sending the current bytes.
So on the server side, you will receive the completed data no interrupted by other new messages from that client, but take in consideration that not all the message sent will be received by one hit if it is too big, but still, it is one message in the end after receiving is finished.
As you are using TCP, the network protocol will ensure that packets are received in the same order as sent.
Regarding thread safety it depends a bit on the actual class which you are using for sending. The declaration part is missing in your provided code fragment.
Given by the name you seem to use Socket and this is thread-safe, so every send is actually atomic, if you use any flavor of Stream, then it is not thread-safe and you need some form of synchronization like a lock, which you are currently using anyway.
If you are sending large packets, then it is important to split the receiving and processing part into two different threads. The TCP buffer is actually a lot smaller than one would think and unfortunately it is not covered inside the logs when it is full as the protocol will keep performing resend until everything has been received.
ALL,
I am using an Asynchronous socket in C#.
My problem is: I want to wait for a callback to finish with connection, because I need to immediately send the information to a server.
Here is a code snippet:
class InternetConnector
{
private struct ConnectionData
{
public Action<Exception> ErrorHandler { get; set; }
public Socket Socket { get; set; }
}
public void ConnectToHost(Action<Exception> errorHandler)
{
IPEndPoint ip = new IPEndPoint(IPAddress.Parse(connector_host), connector_port);
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var ConnectionData = new ConnectionData { ErrorHandler = errorHandler, Socket = client };
client.Blocking = true;
client.BeginConnect(ip, new AsyncCallback(ConnectCallback), ConnectionData);
connectDone.WaitOne(100);
}
private static void ConnectCallback(IAsyncResult ar)
{
ConnectionData connectionData = new ConnectionData();
try
{
connectionData = (ConnectionData)ar.AsyncState;
connectionData.Socket.EndConnect(ar);
connectDone.Set();
Connected = true;
}
catch (Exception e)
{
if (connectionData.ErrorHandler != null)
connectionData.ErrorHandler(e);
}
}
}
public partial class Form1 : Form
{
private bool isRunning = false;
private InternetConnector client = new InternetConnector();
private void AsyncErrorHandler(Exception e)
{
if (status.InvokeRequired)
{
status.BeginInvoke(new Action(() => AsyncErrorHandler(e)));
return;
}
InternetConnector.Connected = false;
isRunning = false;
startStop.Text = "Start";
status.ForeColor = Color.Red;
status.Text = "Socket Error: " + e.Message;
}
private void startStop_Click(object sender, EventArgs e)
{
if (!isRunning || !InternetConnector.Connected)
{
if (!InternetConnector.Connected)
{
client.SetAddress(ipAddress.Text);
client.SetPort(Convert.ToInt32(connectionport.Text));
client.ConnectToHost( AsyncErrorHandler );
status.Text = "Signals Receiver: Connected";
status.ForeColor = Color.Green;
startStop.Text = "Stop";
isRunning = true;
// if connection successful, send some data and start reading the socket
}
else
{
startStop.Text = "Start";
client.DisconnectFromHost(AsyncErrorHandler);
isRunning = false;
}
}
}
}
I can handle the exception in the connection. Now I need to handle the successful connection as well.
Thank you.
You can follow the same pattern, and supply a handler to be called on success as well as on error:
class InternetConnector
{
private struct ConnectionData
{
public Action<Socket> SuccessHandler { get; set; }
public Action<Exception> ErrorHandler { get; set; }
public Socket Socket { get; set; }
}
public void ConnectToHost(Action<Socket> successHandler, Action<Exception> errorHandler)
{
IPEndPoint ip = new IPEndPoint(IPAddress.Parse(connector_host), connector_port);
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var ConnectionData = new ConnectionData
{
SuccessHandler = successHandler,
ErrorHandler = errorHandler,
Socket = client
};
client.Blocking = true;
client.BeginConnect(ip, new AsyncCallback(ConnectCallback), connectionData); // <-- make sure to use the lower-case connectionData here! :)
connectDone.WaitOne(100);
}
private static void ConnectCallback(IAsyncResult ar)
{
ConnectionData connectionData = new ConnectionData();
try
{
connectionData = (ConnectionData)ar.AsyncState;
connectionData.Socket.EndConnect(ar);
connectDone.Set();
Connected = true;
if (connectionData.SuccessHandler != null)
connectionData.SuccessHandler(connectionData.Socket);
}
catch (Exception e)
{
if (connectionData.ErrorHandler != null)
connectionData.ErrorHandler(e);
}
}
}
The signature of the function you pass as a success handler must match the Action<Socket> delegate, which would look something like:
void MySuccessHandler(Socket socket)
{
// do stuff with the connected socket..
Console.WriteLine("Connected to {0}", socket.RemoteEndPoint);
}
void MyErrorHandler(Exception e)
{
Console.WriteLine("Connection error {0}", e.Message);
}
...
myConnector.ConnectToHost(MySuccessHandler, MyErrorHandler);
Maybe some variant of this extension method can inspire. It takes a an action and a timespan and waits for one of task or timeout to complete first.
In case the timeout wins the race, the supplied action is executed.
public static async Task<bool> OnTimeout<T>(this T t, Action<T> action, TimeSpan timespan) where T : Task
{
var timeout = Task.Delay(timespan);
if (await Task.WhenAny(t, timeout) == timeout)
{
//Enter here on timeout
action(t);
return true;
}
else
{
return false;
}
}
Used like this where some actions can be taken in case of a timeout.
await socket.ConnectAsync().OnTimeout(t => {
throw new TimeoutException();
}, TimeSpan.FromSeconds(5));
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?
in this code I'm trying to Listening to multi connection at the same time with Asynchronous
Please how to destroy _receivedata class at this end of this code
class x
{
Thread t1;
int flag = 0;
string receivedPath = "yok";
public delegate void MyDelegate();
BinaryWriter writer;
private void sent_file_Load(object sender, EventArgs e)
{
t1 = new Thread(new ThreadStart(StartListening));
t1.Start();
}
public class StateObject
{
// Client socket.
public Socket workSocket = null;
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
}
public void StartListening()
{
byte[] bytes = new Byte[1024];
IPEndPoint ipEnd = new IPEndPoint(IPAddress.Any, 8221);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(ipEnd);
listener.Listen(100);
if (listener.Connected)
{
allDone.Close();
}
else
{
while (true)
{
allDone.Reset();
listener.BeginAccept(new AsyncCallback(AcceptConn), listener);
allDone.WaitOne();
}
}
}
catch (Exception ex)
{
}
}
public void AcceptConn(IAsyncResult ar)
{
allDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject state = new StateObject();
state.workSocket = handler;
_receivedata rceve = new _receivedata();
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(rceve.ReceiveData), state);
flag = 0;
}
public class _receivedata
{
public void ReceiveData(IAsyncResult ar)
{
some code
//how to destroy this instance of class at the end of this void
}
}
}
when i use this code it destroy all class ,class _receivedata and class x
public class _receivedata : IDisposable
{
public void ReceiveData(IAsyncResult ar)
{
some code
Dispose() ; //it destroy all class ,class _receivedata and class x
}
~_receivedata()
{
Dispose(false);
}
private bool isDisposed = false;
protected void Dispose(bool disposing)
{
if (disposing)
{
// Code to dispose the managed resources of the class
}
// Code to dispose the un-managed resources of the class
isDisposed = true;
this.Dispose(disposing);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Not sure what exactly you are looking for, but C# does have destructors. Despite the name, these act more like finalizers than real destructors (which, by the way don't exist in .NET).
Example:
public class _receivedata
{
public void ReceiveData(IAsyncResult ar)
{
}
public ~ReceiveData()
{
// Finalization logic
}
}