C# Async UDP networking, 10057 error - c#

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.

Related

How does one identify and differentiate clients connected in a client-server socket application?

In the scenario where there is a SINGLE asynchronous socket server, and n-number of clients connected, on the server side how can I differentiate the clients? I need to know which client the data is coming from. Note - It may not be possible to append an identifier to requests.
Clients are created at runtime:
public void CreateSockets()
{
Parallel.For(1, Convert.ToInt32(numericUpDown1.Value) + 1, i =>
{
new Thread(() => Connect(i)).Start();
});
}
Abbreviated client creation loop:
public void Connect(int i)
{
ClientSocket[i] = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
ClientSocket[i].Connect(ip, port);
}
catch (SocketException sex)
{
Console.WriteLine(sex);
}
RequestLoop();
}
The sockets are being created, connect, and are sending data to the server. The server is directly from the MS site examples of Asynchronous Socket Server.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
// State object for reading client data asynchronously
public class StateObject
{
// 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();
// Client socket.
public Socket workSocket = null;
}
public class AsynchronousSocketListener
{
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public static void StartListening()
{
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp );
// Bind the socket to the local endpoint and listen for incoming connections.
try {
listener.Bind(localEndPoint);
listener.Listen(100);
while (true) {
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener );
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket) ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject) ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
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.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, 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 static 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 static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket) ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartListening();
return 0;
}
}
The combination of srcip:srcport:dstip:dstport is a unique value.
Use that Value to identify your client. When a client connects, have the client send an identifier. Maintain state in your server mapping that combination to your client.
You will never have two identical values of this on any socket on your network. (Except in the case of private networks with identical ip addresses).

C# Async Socket Server - BeginReceive in Callback

I have a simple asynchronous socket server written in C# (pretty much Microsoft's example), however the issue with this example is that it accepts only one message from a client and then shuts down. I want this server to stay alive after receiving any message.
This question has been asked before here, and the answer & comments explain that the resolution to this is simply to call handler.beginReceive within the SendCallback function, however to do this requires passing in a state variable. This is something I am unsure of doing with Async programming as I'm pretty new to it.
With the example below, how can I carry my state object from the Send function to the SendCallback function?
Server code:
// Asynchronous Server Socket Example
// http://msdn.microsoft.com/en-us/library/fx6588te.aspx
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
// State object for reading client data asynchronously
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 GetState
{
}
public class AsynchronousSocketListener
{
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public static void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
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 != null)
{
// All the data has been read from the
// client. Display it on the console.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, content);
// Echo the data back to the client.
Send(handler, content, state);
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
}
}
private static void Send(Socket handler, String data, StateObject state)
{
// 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 static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
/// ******* WIP ******** //
//handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
//handler.Shutdown(SocketShutdown.Both);
//handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartListening();
return 0;
}
}
This is how I would do it:
public class AsynchronousSocketServer
{
private Socket listener;
private byte[] buffer = new byte[8192]; // Buffer to store data from clients.
public void StartListening()
{
listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(new IPEndPoint(localIPAddress, listeningPort));
listener.Listen(20);
listener.BeginAccept(OnSocketAccepted, null);
}
private void OnSocketAccepted(IAsyncResult result)
{
// This is the client socket, where you send/receive data from after accepting. Keep it in a List<Socket> collection if you need to.
Socket client = listener.EndAccept(result);
// Pass in the client socket as the state object, so you can access it in the callback.
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, OnDataReceived, client); // Start receiving data from this client.
listener.BeginAccept(OnSocketAccepted, null); // Start a new async accept operation to accept incoming connections from other clients.
}
private void OnDataReceived(IAsyncResult result)
{
// This is the client that sent you data. AsyncState is exactly what you passed into the state parameter in BeginReceive
Socket client = result.AsyncState as Socket;
int received = client.EndReceive(result);
// Handle received data in buffer, send reply to client etc...
// Start a new async receive on the client to receive more data.
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, OnDataReceived, client);
}
}
As you can see it's pretty much a lot of recursive callbacks. The basic idea is that you call BeginAccept to start accepting the first connection, then once your callback fires you accept the connection with EndAccept and start a new BeginAccept to start accepting more connections. This same logic applies to BeginReceive and EndReceive when you start communicating with the clients. With this logic the server will continuously accept incoming connections and clients will also be able to continously send data to server.
In your example you get your listener from the AsyncState but you didn't call BeginAccept again to accept more incoming connections, which probably explains why your server only accepts 1 connection and shuts down.
For the state parameter in BeginSend, you can actually just put your BeginReceive right after your Send() method to save yourself the hassle:
Send(handler, content, state);
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
It's much better to just fire up a background thread and use blocking calls.
Here's a TcpServer using the TcpListener and NetworkStream
public class TcpServer
{
public void Run(string address, int port)
{
var listener = new TcpListener(IPAddress.Parse(address), port);
listener.Start();
while (true)
{
TcpClient tcpclient = null;
NetworkStream netstream = null;
try
{
tcpclient = listener.AcceptTcpClient();
Console.WriteLine("Client connected from " + tcpclient.Client.LocalEndPoint.ToString());
netstream = tcpclient.GetStream();
var responsewriter = new StreamWriter(netstream) { AutoFlush = true };
while (true)
{
if (IsDisconnected(tcpclient))
throw new Exception("Client disconnected gracefully");
if (netstream.DataAvailable) // handle scenario where client is not done yet, and DataAvailable is false. This is not part of the tcp protocol.
{
string request = Read(netstream);
Console.WriteLine("Client sent: " + request);
responsewriter.Write("You sent: " + request);
}
}
}
catch (Exception ex)
{
netstream.Close();
tcpclient.Close();
Console.WriteLine(ex.Message);
}
}
}
private bool IsDisconnected(TcpClient tcp)
{
if (tcp.Client.Poll(0, SelectMode.SelectRead))
{
byte[] buff = new byte[1];
if (tcp.Client.Receive(buff, SocketFlags.Peek) == 0)
return true;
}
return false;
}
private string Read(NetworkStream netstream)
{
byte[] buffer = new byte[1024];
int dataread = netstream.Read(buffer, 0, buffer.Length);
string stringread = Encoding.UTF8.GetString(buffer, 0, dataread);
return stringread;
}
}
To run it
static void Main()
{
ThreadPool.QueueUserWorkItem(w => {
var asyncserver = new TcpServer();
asyncserver.Run("192.168.0.7", 5055); // or whatever your local IP Address is
});
Console.WriteLine("Press [Enter] to quit");
Console.ReadLine();
}

Trying to Connect RPI to Unity via TCP

I am working on a small project and I am at the point where I want to connect my Raspberry Pi to Unity (running on my PC). I am able to make a connection running Visual Studio, but when I run the same code in Unity, no connections happen.
C# Code
using System;
using System.Globalization;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
// State object for reading client data asynchronously
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 {
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener() {
}
public static void StartListening() {
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
//IPAddress ipAddress = Array.Find(ipHostInfo.AddressList, x => x.AddressFamily == AddressFamily.InterNetwork);
IPAddress ipAddress = IPAddress.Any;
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 6670);
Console.WriteLine($"Connected on {localEndPoint}");
// Create a TCP/IP socket.
Socket listener = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp );
// Bind the socket to the local endpoint and listen for incoming connections.
try {
listener.Bind(localEndPoint);
listener.Listen(100);
while (true) {
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener );
Console.WriteLine("Accepted");
// Wait until a connection is made before continuing.
allDone.WaitOne();
Console.WriteLine("After wait");
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar) {
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket) ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar) {
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject) ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0) {
// There might be more data, so store the data received so far.
var stringRead = Encoding.ASCII.GetString(
state.buffer, 0, bytesRead);
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.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, content );
// Echo the data back to the client.
Send(handler, content);
} else {
string timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss.fff",
CultureInfo.InvariantCulture);
Console.WriteLine(timestamp + ": " + stringRead);
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
//Test Code
Send(handler, "boogieboogie");
}
}
}
private static 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 static void SendCallback(IAsyncResult ar) {
try {
// Retrieve the socket from the state object.
Socket handler = (Socket) ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
//handler.Shutdown(SocketShutdown.Both);
//handler.Close();
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args) {
Thread t = new Thread(StartListening);
t.Start();
//FingerMovement.Service();
return 0;
}
}
The Python code is just doing a socket connect to the IP and port.
So to restate the question: Why does it not connect to the RPI when I run this in Unity? No connections occur, however, if I run the same exact code through VS, it connects just fine.
I allowed Unity in my firewall, tried running it in Admin, still nothing.
It's a bit of a long shot but have you enabled 'run in the background' checkbox in the player settings? I've had unity miss a whole lot of system events / transmissions while I was switching windows when this was off. I think all the child processes freeze when Unity looses focus by default, and I think that inclueds the async quasi-processes, or at the very least it surely includes your main thread which communicates with you

Close Client after the server respond

The only thing i want to change is to close the client connection after the client send message to the server and received respond from the server.
what i need to change in the client code ?
Server
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
// State object for reading client data asynchronously
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
{
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public static void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
//IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
//IPAddress ipAddress = ipHostInfo.AddressList[0];
IPAddress ipAddress = System.Net.IPAddress.Loopback;
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 3000);
// 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 (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
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.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, 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 static 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 static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartListening();
return 0;
}
}
Client:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class Program
{
public static ManualResetEvent connectDone = new ManualResetEvent(false);
public static ManualResetEvent sendDone = new ManualResetEvent(false);
public static ManualResetEvent receiveDone = new ManualResetEvent(false);
public static void Connect(EndPoint remoteEP, Socket client)
{
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Send(Socket client, 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.
client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None,
new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
// Signal that all bytes have been sent.
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
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));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
else
{
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
string response = state.sb.ToString();
Console.WriteLine(response);
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
static void Main(string[] args)
{
IPAddress ipAddress = System.Net.IPAddress.Loopback;
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 3000);
Socket sock = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
Connect(localEndPoint, sock);
string packet;
while (true)
{
packet = Console.ReadLine();
packet += "<EOF>";
Send(sock, packet);
Receive(sock);
connectDone.WaitOne();
}
}
}
The while loop in Main will run indefinitely.
while (true)
{
packet = Console.ReadLine();
packet += "<EOF>";
Send(sock, packet);
Receive(sock);
connectDone.WaitOne();
}
either remove it entirely (so that it runs only once) or add in a condition to exit the while loop.
as Diego pointed out the in the comments, you should close the socket after you are done, by
sock.Close();

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