Multiple TcpListeners not working - c#

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.

Related

Thread sending data to wrong client. Is this a thread safety issue?

I'm currently developing a server that deals with clients using a consumer/producer approach with threads and a blocking collection as shown below:
public class NetworkClient
{
private bool _started = false;
private int _clientId;
private readonly Socket _socket;
private static AutoResetEvent _lastMessageWasAckd = new AutoResetEvent(true);
private static BlockingCollection<byte[]> _messageQueue = new BlockingCollection<byte[]>();
public NetworkClient(Socket socket, int clientId)
{
this._socket = socket;
this._clientId = clientId;
}
public int getClientID() {
return _clientId;
}
public void SendMessage(string message)
{
Console.WriteLine("Adding to player's sending queue " + _clientId);
_messageQueue.Add(Encoding.ASCII.GetBytes(message));
}
public void Start()
{
Thread receiver = new Thread(new ThreadStart(ReceivingThreadProc));
Thread sender = new Thread(new ThreadStart(SendingThreadProc));
receiver.Start();
sender.Start();
this._started = true;
}
public void Stop()
{
this._started = false;
}
private void ReceivingThreadProc()
{
byte[] bytes = new byte[1024];
string data;
try
{
while (_started && _socket.Connected)
{
int numByte = this._socket.Receive(bytes);
data = Encoding.ASCII.GetString(bytes, 0, numByte);
if (numByte == 0)
{
break;
}
if (data == "ACK")
{
_lastMessageWasAckd.Set();
continue;
}
// Acknowledge the message
_socket.Send(Encoding.ASCII.GetBytes("ACK"));
ServerReceiver.onEvent(this._clientId, data);
}
}
catch (Exception e)
{
this._socket.Close();
}
}
private void SendingThreadProc()
{
while (_started && _socket.Connected)
{
_lastMessageWasAckd.WaitOne();
byte[] message = _messageQueue.Take();
Console.WriteLine("Sending the following message to client number: " + _clientId);
Console.WriteLine(System.Text.Encoding.ASCII.GetString(message));
_socket.Send(message);
_lastMessageWasAckd.Reset();
}
}
}
There will be an instance of NetworkClient created for every client that connects for the server. The issue is that sometimes a message is queued to be sent to client 1 (this is confirmed by the Console.Writeline in the SendMessage method) however that message is sent to client 0 (Shown by the console writeline in the SendingThreadProc method) instead. Is this due to a thread safety issue, or am I missing something entirely? This typically happens when two messages are sent right after one another.
Any help would be greatly appreciated.
EDIT:
As many people rightly pointed out I haven't added where I call SendMessage I'll put this class down below:
class NetworkServer
{
private int latestClient = 0;
private ServerReceiver _serverReceiver;
private static readonly Dictionary<int, NetworkClient> clients = new Dictionary<int, NetworkClient>();
public NetworkServer()
{
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 5656);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
this._serverReceiver = new ServerReceiver();
this._serverReceiver.start();
try
{
listener.Bind(endpoint);
listener.Listen(10);
while (true)
{
Socket clientSocket = listener.Accept();
this.OnClientJoin(clientSocket);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static void SendClientMessage(int clientId, string package, CommandType commandType,
Dictionary<string, object> data = null)
{
if (data == null)
{
data = new Dictionary<string, object>();
}
SendClientMessageRaw(clientId, new NetworkCommand(clientId, package, commandType, data).ToJson());
}
public static void SendClientMessageRaw(int id, string message)
{
Console.WriteLine("Supposed to send to client number " + clients[id].getClientID());
clients[id].SendMessage(message);
}
private void OnClientJoin(Socket socket)
{
// Add client to array, perform handshake?
NetworkClient networkClient = new NetworkClient(socket, latestClient);
clients.Add(latestClient, networkClient);
Console.WriteLine("player added :" + latestClient);
networkClient.Start();
latestClient++;
if (latestClient == 2)
{
SendClientMessage(1, "Test", CommandType.Ping, null);
}
}
Could it be because your message queue is static and therefore shared between all NetworkClients? Meaning client A can pick up a message for client B?
Might be as easy as removing static from the properties.

How to implement Socket server that accept more message

I want to send at real time some data from Android application to server.
So I'm building a simple socket Server in c# like this:
class Program
{
private Socket listener;
static void Main(string[] args)
{
Program p = new Program();
p.socketServer();
}
public void socketServer()
{
int MAXBUFFER = 1024;
Console.WriteLine("SOCKET STARTED");
listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(new IPEndPoint(IPAddress.Any, 8080));
listener.Listen(10);
while (true)
{
Console.WriteLine("WAITING CONNECTION");
Socket socket = listener.Accept();
string receivedMessage = string.Empty;
while (true)
{
byte[] receivedBytes = new byte[MAXBUFFER];
int numBytes = socket.Receive(receivedBytes);
receivedMessage += Encoding.ASCII.GetString(receivedBytes, 0, numBytes);
if (receivedMessage.IndexOf("\n") > -1)
{
Console.WriteLine("MESSAGE FROM CLIENT: {0}", receivedMessage);
//break;
}
}
Console.WriteLine("MESSAGE FROM CLIENT: {0}", receivedMessage);
string replyMessage = "MESSAGE RECEIVED";
byte[] replyBytes = Encoding.ASCII.GetBytes(replyMessage);
}
}
public void shutdownServer()
{
listener.Shutdown(SocketShutdown.Both);
listener.Close();
}
}
And I'm building this class to send data from Android application:
public class TcpClient {
public static final String SERVER_IP = "192.168.110.50"; // computer IP address
public static final int SERVER_PORT = 8080;
private String mServerMessage;
private OnMessageReceived mMessageListener = null;
private boolean mRun = false;
private PrintWriter mBufferOut;
private BufferedReader mBufferIn;
private Socket socket;
/**
* Constructor of the class. OnMessagedReceived listens for the messages received from server
*/
public TcpClient(OnMessageReceived listener) {
mMessageListener = listener;
}
/**
* Sends the message entered by client to the server
*
* #param message text entered by client
*/
public void sendMessage(String message) {
socket.isConnected();
if (mBufferOut != null /*&& !mBufferOut.checkError()*/) {
mBufferOut.println(message);
}
}
/**
* Close the connection and release the members
*/
public void stopClient() {
Log.i("Debug", "stopClient");
// send mesage that we are closing the connection
//sendMessage(Constants.CLOSED_CONNECTION + "Kazy");
mRun = false;
if (mBufferOut != null) {
mBufferOut.flush();
mBufferOut.close();
}
mMessageListener = null;
mBufferIn = null;
mBufferOut = null;
mServerMessage = null;
}
public void run() {
mRun = true;
try {
//here you must put your computer's IP address.
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
//create a socket to make the connection with the server
socket = new Socket(SERVER_IP, SERVER_PORT);
//socket.connect(socket.getRemoteSocketAddress());
socket.isConnected();
try {
Log.i("Debug", "inside try catch");
mBufferOut = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())),
true);
} catch (Exception e) {
Log.e("TCP", "S: Error", e);
} finally {
}
} catch (Exception e) {
Log.e("TCP", "C: Error", e);
}
}
public interface OnMessageReceived {
public void messageReceived(String message);
}
}
And in the MainActivity I use this code:
tcpClient = new TcpClient(new TcpClient.OnMessageReceived() {
#Override
//here the messageReceived method is implemented
public void messageReceived(String message) {
//this method calls the onProgressUpdate
//publishProgress(message);
}
});
tcpClient.run();
After connect to server i user this code to send message:
for(int i=0; i<10; i++){
tcpClient.sendMessage("test " + i);
}
The problem is that only the first message arrive to the server. I think that the problem is on the socket server that lost the connection with the client.

Can I start multiple TcpListener BeginAcceptTcpClient asynchronous operations

Does starting many asynchronous operations could be a problem?
I'am writing TCP server where number of concurrent clients is upper bounded. I've came up with idea where server contains certain number of slots. Each slot starts asynchronous BeginAcceptTcpClient call on shared TcpListener instance. When client connects, first available asynchronous operation will return by callback. Then I can handle TcpClient instance and reanable slot by calling BeginAcceptTcpClient once again. With such architecture I don't have to manually care about synchronising counter to limit client connections. Incomming connection waits for reeanbling slots. But I'm not sure is it a good idea at all.
Sample console program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace SlotTcpServerSample
{
internal class Program
{
private class Slot : IDisposable
{
private TcpListener _listener;
private EventWaitHandle _closed;
public Slot(TcpListener listener)
{
_listener = listener;
_closed = new ManualResetEvent(false);
}
public void Open(AsyncCallback callback)
{
_listener.BeginAcceptTcpClient(callback, this);
}
public void Close()
{
_closed.Set();
}
public void WaitForClose()
{
_closed.WaitOne();
}
public void Dispose()
{
_closed.Close();
}
}
private class TcpServer
{
private const int MAX = 10;
private object _sync;
private Slot[] _slots;
private IPEndPoint _endpoint;
private TcpListener _listener;
public TcpServer(IPEndPoint endpoint)
{
_sync = new object();
_endpoint = endpoint;
}
public void Start()
{
lock (_sync)
{
if (_listener != null)
return;
_listener = new TcpListener(_endpoint);
_slots = new Slot[MAX];
for (int i = 0; i < MAX; i++)
_slots[i] = new Slot(_listener);
_listener.Start();
foreach (Slot slot in _slots)
slot.Open(HandleConnection);
}
}
public void Stop()
{
lock (_sync)
{
if (_listener == null)
return;
_listener.Stop();
foreach (Slot slot in _slots)
{
slot.WaitForClose();
slot.Dispose();
}
_listener = null;
}
}
private void HandleConnection(IAsyncResult asyncResult)
{
Slot slot = (Slot)asyncResult.AsyncState;
TcpClient client = null;
try
{
client = _listener.EndAcceptTcpClient(asyncResult);
}
catch (ObjectDisposedException ex)
{
slot.Close();
return;
}
HandleClient(client);
try
{
slot.Open(HandleConnection);
}
catch (ObjectDisposedException ex)
{
slot.Close();
return;
}
}
private void HandleClient(TcpClient client)
{
Console.WriteLine("Connected: {0}", client.Client.RemoteEndPoint.ToString());
client.Close();
}
}
private static void Main(string[] args)
{
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 8080);
TcpServer server = new TcpServer(endpoint);
try
{
Console.WriteLine("Starting...");
server.Start();
Console.WriteLine("Started");
Console.ReadLine();
Console.WriteLine("Stopping...");
server.Stop();
Console.WriteLine("Stopped");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}

C# async SocketException while binding

I am working on a client-server application on C# using async sockets. As I listen for connections, I keep getting this error
An unhandled exception of type 'System.Net.Sockets.SocketException'
occurred in System.dll
Additional information: Only one usage of each socket address (protocol/network address/port) is normally permitted
This is the line where this exception happens:
_listener.Bind(new IPEndPoint(0, port));
The code is under Listener.Start(int port). In the main program, here's how I call the method:
void btnListen_Click(object sender, EventArgs e)
{
_listener = new Listener();
_listener.Accepted += new Listener.SocketAcceptedHandler(listener_Accepted);
_listener.Start(8192);
}
I am testing both the client and server applications in my PC.
Here's the Listener class.
namespace serverPC
{
class Listener
{
public delegate void SocketAcceptedHandler(Socket e);
public event SocketAcceptedHandler Accepted;
Socket _listener;
public int Port;
public bool Running
{
get;
private set;
}
public Listener() {Port = 0;}
public void Start(int port)
{
if (Running)
return;
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_listener.Bind(new IPEndPoint(0, port)); // This is where the SocketException error occurs
_listener.Listen(0);
_listener.BeginAccept(acceptedCallback, null);
Running = true;
}
public void Stop()
{
if (!Running)
return;
_listener.Close();
Running = false;
}
void acceptedCallback(IAsyncResult ar)
{
try
{
Socket s = _listener.EndAccept(ar);
if (Accepted != null)
{
Accepted(s);
}
}
catch
{
}
if (Running)
{
try
{
_listener.BeginAccept(acceptedCallback, null);
}
catch
{
}
}
}
}
}
Here's the Client class.
namespace serverPC
{
struct ReceiveBuffer
{
public const int BUFFER_SIZE = 1024;
public byte[] Buffer;
public int ToReceive;
public MemoryStream BufStream;
public ReceiveBuffer(int toRec)
{
Buffer = new byte[BUFFER_SIZE];
ToReceive = toRec;
BufStream = new MemoryStream(toRec);
}
public void Dispose()
{
Buffer = null;
ToReceive = 0;
Close();
if (BufStream != null)
BufStream.Dispose();
}
public void Close()
{
if (BufStream != null && BufStream.CanWrite)
{
BufStream.Close();
}
}
}
class Client
{
byte[] lenBuffer;
ReceiveBuffer buffer;
Socket _socket;
public IPEndPoint EndPoint
{
get
{
if (_socket != null && _socket.Connected)
{
return (IPEndPoint)_socket.RemoteEndPoint;
}
return new IPEndPoint(IPAddress.None, 0);
}
}
public delegate void DisconnectedEventHandler(Client sender);
public event DisconnectedEventHandler Disconnected;
public delegate void DataReceivedEventHandler(Client sender, ReceiveBuffer e);
public event DataReceivedEventHandler DataReceived;
public Client(Socket s)
{
_socket = s;
lenBuffer = new byte[4];
}
public void Close()
{
if (_socket != null)
{
_socket.Disconnect(false);
_socket.Close();
}
buffer.Dispose();
_socket = null;
lenBuffer = null;
Disconnected = null;
DataReceived = null;
}
public void ReceiveAsync()
{
_socket.BeginReceive(lenBuffer, 0, lenBuffer.Length, SocketFlags.None, receiveCallback, null);
}
void receiveCallback(IAsyncResult ar)
{
try
{
int rec = _socket.EndReceive(ar);
if (rec == 0)
{
if (Disconnected != null)
{
Disconnected(this);
return;
}
if (rec != 4)
{
throw new Exception();
}
}
}
catch (SocketException se)
{
switch (se.SocketErrorCode)
{
case SocketError.ConnectionAborted:
case SocketError.ConnectionReset:
if (Disconnected != null)
{
Disconnected(this);
return;
}
break;
}
}
catch (ObjectDisposedException)
{
return;
}
catch (NullReferenceException)
{
return;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
buffer = new ReceiveBuffer(BitConverter.ToInt32(lenBuffer, 0));
_socket.BeginReceive(buffer.Buffer, 0, buffer.Buffer.Length, SocketFlags.None, receivePacketCallback, null);
}
void receivePacketCallback(IAsyncResult ar)
{
int rec = _socket.EndReceive(ar);
if (rec <= 0)
{
return;
}
buffer.BufStream.Write(buffer.Buffer, 0, rec);
buffer.ToReceive -= rec;
if(buffer.ToReceive > 0)
{
Array.Clear(buffer.Buffer, 0, buffer.Buffer.Length);
_socket.BeginReceive(buffer.Buffer, 0, buffer.Buffer.Length, SocketFlags.None, receivePacketCallback, null);
return;
}
if (DataReceived != null)
{
buffer.BufStream.Position = 0;
DataReceived(this, buffer);
}
buffer.Dispose();
ReceiveAsync();
}
}
}
Why do I get the SocketException error? Any help is appreciated. Thanks!
So the obvious things to check - Something is already listening on port 8192 or there's some other reason why your machine would reject your program opening that port (firewalls, etc).
The other problem is while you are blocking binding twice with the "Running" check, you're only doing that for the instance of listener - hitting the button will create a whole new listener and attempt to have it listen on port 8192 - which since you already have a listener bound there, will fail with that exception.

Is it possible to wait for connection on asynchronous socket

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));

Categories

Resources