Async Sockets and cleaning up resources - c#

If I have a callback from a
listener.BeginAcceptSocket(cbConnect, listener);
and my callback method:
private void cbConnect(IAsyncResult ar)
{
TcpListener listener = (TcpListener)ar.AsyncState;
MyObj myObj = new MyObj();
myObj.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
myObj.socket = listener.EndAcceptSocket(ar);
listener.BeginAcceptSocket(cbConnect, listener);//start listening again
myObj.socket.BeginReceive(myObj.buffer, 0, myObj.buffer.Length, 0, cbReceive, myObj);
}
Here is MyObj class:
Public class MyObj
{
public Socket socket;
public byte[] buffer = new byte[1080];
}
My question is if the client on the other end of the connection never sends any data what will happen to myObj?
How would I close the socket and mop up resources?

If the remote connection drops, the socket should cleanup on it's own via the Garbage Collector.

Related

Save connected Socket in Dictionary

I'm trying to save a connected socket in a dictionary so my API doesn't have to create a new connection every time. My problem is that the socket gets disposed.
So when I call GetConnection() a second time socket.connected is false and socket.Available.Message is "Cannot access a disposed object. Object name: 'System.Net.Sockets.Socket'.".
public static class ModbusSocket
{
private static Dictionary<IPAddress, Socket> socketList;
public static Socket GetConnection(string server, int port)
{
if (socketList is null)
{
socketList = new Dictionary<IPAddress, Socket>();
}
IPAddress iPAddress = IPAddress.Parse(server);
if (socketList.ContainsKey(iPAddress))
{
var socket = socketList[iPAddress];
if (socket.Connected)
{
return socket;
}
else
{
socketList.Remove(iPAddress);
socket = new Socket(iPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipe = new IPEndPoint(iPAddress, port);
socket.Connect(ipe);
socketList.Add(iPAddress, socket);
return socket;
}
}
else
{
Socket socket = new Socket(iPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipe = new IPEndPoint(iPAddress, port);
socket.Connect(ipe);
socketList.Add(iPAddress, socket);
return socket;
}
}
}
OMG I found the issue...
I invoked it with using:
using (Socket s = ModbusSocket.GetConnection(hostIp, port))
{
var telegram = new Telegram();
telegram.Set(0, AddressConst.PositionWindow, 4);
var response = telegram.SendAndReceive(s);
var result = BitConverter.ToInt32(new byte[] { response.Byte19, response.Byte20, response.Byte21, response.Byte22 }, 0);
return result;
}

Why is my C# Socket server not allowing multiple instances of the client to connect, only from the local machine?

I have previously had this code working, and am unsure of the cause of the issue i am currently having. I am writing a simple client/server application for encrypted chat. The server allows for multiple simultaneous clients. When i bind the server to the local IP Address i can connect with multiple local clients simultaneously, but when I bind it to the external IP address, only the first instance on the local machine will connect, but other devices may connect with multiple instances simultaneously. In this case even closing the first instance will not allow another to connect, and the AcceptCallBack is never called. I have been unable to find any other reports of this issue. Reasons that come to mind include that I made some sort of mistake in the code, or I need to separately listen for local connections and remote connections, or that it is a router/firewall issue.
For my server i have:
public partial class frmServer : Form
{
Thread listenThread;
private static bool listening = false;
private static List<StateObject> Users = new List<StateObject>();
public frmServer()
{
InitializeComponent();
}
private void frmServer_Load(object sender, EventArgs e)
{
listenThread = new Thread(new ThreadStart(StartListening));
listenThread.Start();
}
public static void StartListening()
{
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 19541);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
listening = true;
while (true)
{
//check if there are new connections
if (!listening)
{
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
listening = true;
}
Thread.Sleep(50);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static void AcceptCallback(IAsyncResult ar)
{
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
listening = false;
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
Users.Add(state);
}
}
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
//user info
}
And For the client i have
public partial class frmClient : Form
{
public frmClient()
{
InitializeComponent();
}
private void frmClient_Load(object sender, EventArgs e)
{
StartClient();
}
private void StartClient()
{
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
IPHostEntry ipHostInfo = Dns.GetHostEntry("Remote Host Address");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// Create a TCP/IP V4 socket.
Socket client = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
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.
Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}

C# Async UDP networking, 10057 error

I have been trying to get this asynchronous UDP server working for the past two days and am banging my head against the wall now.
I am currently running into getting a SocketException for 10057 when I am trying to get RemoteEndPoint from the Socket in the ReceiveCallback.
When looking with the debugger socket is filled, state is filled. LocalEndPoint is normally set to {0.0.0.0:53}, yet RemoteEndPoint says a SocketException was thrown. And I do not understand what I am missing in my set up. Any helps, tips, guidance welcome.
namespace UDPServer
{
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
public class StateObject
{
// Client socket
public Socket socket = null;
// Size of the receive buffer
public const int BufferSize = 1024;
// Receive buffer
public byte[] buffer = new byte[BufferSize];
}
public class ServerAsync
{
private static int portNumber = 53;
public static ManualResetEvent WaitEvent = new ManualResetEvent(false);
public static void StartListening()
{
// Data buffer
byte[] bytes = new byte[1024];
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, portNumber);
EndPoint client = new IPEndPoint(IPAddress.Any, 0);
socket.Bind(localEndPoint);
Console.WriteLine("Listening for UDP queries on port 53");
while (true)
{
// Set event to non-signaled state.
WaitEvent.Reset();
Console.WriteLine("Waiting for a connection...");
StateObject state = new StateObject();
state.socket = socket;
socket.BeginReceiveFrom(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, ref client, new AsyncCallback(ReceiveCallback), state);
// Wait until a connection is made before continuing.
WaitEvent.WaitOne();
}
}
public static void ReceiveCallback(IAsyncResult ar)
{
// Signal main thread to continue.
WaitEvent.Set();
int bytesRead = 0;
try
{
if (ar.IsCompleted)
{
StateObject state = (StateObject)ar.AsyncState;
Socket socket = state.socket;
IPEndPoint sender = (IPEndPoint)socket.RemoteEndPoint;
EndPoint remoteEndPoint = (EndPoint)sender;
bytesRead = socket.EndReceiveFrom(ar, ref remoteEndPoint);
if (bytesRead > 0)
{
Console.WriteLine("Received {0} bytes from {1}:{2}: {3}", bytesRead, sender.Address.ToString(), sender.Port.ToString(), BitConverter.ToString(state.buffer));
socket.BeginReceiveFrom(state.buffer, 0, StateObject.BufferSize, 0, ref remoteEndPoint, new AsyncCallback(ReceiveCallback), state);
}
}
}
catch (SocketException se)
{
Console.WriteLine("SocketException: " + se.ErrorCode + ": " + se.Message);
}
catch (ObjectDisposedException ode)
{
Console.WriteLine("Socket closed: " + ode.Message);
}
}
public static void Main(string[] args)
{
Console.WriteLine("Server starting up...");
StartListening();
}
}
}
Why is your main thread looping and reading from the port when the EndCallback is also starting a new read? It looks to me like two threads will be trying to read from the port simultaneously, using the same StateObject.
Also, your receive callback is using the AsyncResult's buffer to start a new read operation. Do you know what the socket does with the AsyncResult object after you return? Can you be sure it doesn't dispose it? You may need to create a new AsyncResult for each read request so that they remain truly independent.

A request to send or receive data was disallowed because the socket is not connected . .

After a long break, i tried to refresh my memory of System.Net.Sockets but i am encountering problems with just connect even 2 machines.
Exception: 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
Server Code:
private void startButton_Click(object sender, EventArgs e)
{
LocalEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.103"), 4444);
_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_Socket.Bind(LocalEndpoint);
_Socket.Listen(10);
_Socket.BeginAccept(new AsyncCallback(Accept), _Socket);
}
private void Accept(IAsyncResult _IAsyncResult)
{
Socket AsyncSocket = (Socket)_IAsyncResult.AsyncState;
AsyncSocket.EndAccept(_IAsyncResult);
buffer = new byte[1024];
AsyncSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Receive), AsyncSocket);
}
private void Receive(IAsyncResult _IAsyncResult)
{
Socket AsyncSocket = (Socket)_IAsyncResult.AsyncState;
AsyncSocket.EndReceive(_IAsyncResult);
strReceive = Encoding.ASCII.GetString(buffer);
Update_Textbox(strReceive);
buffer = new byte[1024];
AsyncSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Receive), AsyncSocket);
}
Client Code:
private void connectButton_Click(object sender, EventArgs e)
{
RemoteEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.103"), 4444);
_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_Socket.BeginConnect(RemoteEndPoint, new AsyncCallback(Connect), _Socket);
}
private void Connect(IAsyncResult _IAsyncResult)
{
Socket RemoteSocket = (Socket)_IAsyncResult.AsyncState;
RemoteSocket.EndConnect(_IAsyncResult);
}
The error is due to following line in your Accept function:
AsyncSocket.EndAccept(_IAsyncResult);
Server listens to a particular socket and it uses it to accept connections from the client. You can not use same socket to accept connections and receive data from the client. If you look at the help of Socket.EndAccept it says that it creates a new Socket to handle remote host communication. In your code you are using _Socket to listen for client connections and to receive data. You can modify this line to:
Socket dataSocket = AsyncSocket.EndAccept(_IAsyncResult);
You also need to pass this new socket to BeginReceive function parameter as:
AsyncSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(Receive), dataSocket);

Stopping an asynchronous TCP server on separate thread in C#

I have implemented an asynchronous TCP server that is spawned by another process. It starts fine and operates as expected, however I am having trouble terminating the server when I end the process that started it.
The following is my current TCP server and stopping function from the other process.
TCP Server
public class StateObject
{
//Client socket.
public Socket workSocket = null;
//Size of receive buffer.
public const int BufferSize = 1024;
//Receive buffer.
public byte[] buffer = new byte[BufferSize];
//Received data string.
public StringBuilder sb = new StringBuilder();
}
public class AsynchronousSocketListener : Strategy
{
//Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public volatile bool listening = true;
//User-specified port number.
private int Port;
public AsynchronousSocketListener(int port)
{
Port = port;
}
public void StopListening()
{
listening = false;
}
public void StartListening()
{
//Data buffer for incoming data.
byte[] bytes = new Byte[1024];
//Establish the local endpoint for the socket.
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, Port);
//Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
//Bind the socket to the local endpoint and listen for
//incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (listening)
{
//Set the event to nonsignaled state.
allDone.Reset();
//Start an asychronous socket to listen for connections.
Print("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
//Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Print(e.ToString());
}
}
public void AcceptCallback(IAsyncResult arg)
{
//Signal the main thread to continue.
allDone.Set();
//Get the socket that handles the client request.
Socket listener = (Socket) arg.AsyncState;
Socket handler = listener.EndAccept(arg);
//Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public void ReadCallback(IAsyncResult arg)
{
String content = String.Empty;
//Retrieve the state object and the handler socket
//from the asynchronous state object.
StateObject state = (StateObject) arg.AsyncState;
Socket handler = state.workSocket;
//Read data from the client socket.
int bytesRead = handler.EndReceive(arg);
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.
content = state.sb.ToString();
if (content.IndexOf("<EOF>") > -1)
{
//All the data has been read from the
//client. Display it on the console.
Print("Read " + content.Length + " bytes from socket. \n Data : " + content);
//Echo the data back to the client.
Send(handler, content);
}
else
{
//Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
private 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,
new AsyncCallback(SendCallback),handler);
}
private void SendCallback(IAsyncResult arg)
{
try
{
//Retrieve the socket from the state object.
Socket handler = (Socket) arg.AsyncState;
//Complete sending the data to the remote device.
int bytesSent = handler.EndSend(arg);
Print("Sent " + bytesSent + " bytes to client.");
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Print(e.ToString());
}
}
}
Spawning process
//private NinjaTerminal.Server server;
private NinjaTerminal.AsynchronousSocketListener server;
private Thread listenThread;
private int _Port = 8080;
protected override void OnStartUp()
{
server = new NinjaTerminal.AsynchronousSocketListener(Port);
listenThread = new Thread(new ThreadStart(server.StartListening));
listenThread.Start();
}
protected override void OnTermination()
{
listenThread.stopListening();
listenThread.Join();
}
Now I've verified that OnTermination() gets called, and it does join to the server thread, however the server thread never ends.
I would love some insights as to why, and suggestions to a better architecture or more than welcome. At this stage I haven't invested much into anything but setting up the TCP server, so if you have a different/better idea I'd love to hear it.
Also, I've searched high and low through StackOverflow for an answer already and none of them really applied to an asynchronous TCP server. And I'm using .NET 3.5
Code addition to Reed's answer
public void StopListening()
{
listening = false;
allDone.Set();
}
public void StartListening()
{
//Data buffer for incoming data.
byte[] bytes = new Byte[1024];
//Establish the local endpoint for the socket.
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, Port);
//Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
//Bind the socket to the local endpoint and listen for
//incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (listening)
{
//Set the event to nonsignaled state.
allDone.Reset();
//Start an asychronous socket to listen for connections.
Print("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
//Wait until a connection is made before continuing.
allDone.WaitOne();
}
listener.Close();
}
catch (Exception e)
{
Print(e.ToString());
}
}
You need to change StopListening to also include a call to signal your WaitHandle:
public void StopListening()
{
this.listening = false;
this.allDone.Set();
}
Without this, your StartListening routine will hang forever here:
//Wait until a connection is made before continuing.
allDone.WaitOne();

Categories