Socket Programming multiple client one server - c#

I am just starting out Socket Programming in C# and am now a bit stuck with this problem.
How do you handle multiple clients on a single server without creating a thread for each client?
The one thread for each client works fine when there are say 10 clients but if the client number goes up to a 1000 clients is creating a thread for every single one of them advisable? If there is any other method to do this can someone please tel me?

Try to use asynchronous server.
The following example program creates a server that receives connection requests from clients. The server is built with an asynchronous socket, so execution of the server application is not suspended while it waits for a connection from a client. The application receives a string from the client, displays the string on the console, and then echoes the string back to the client. The string from the client must contain the string <EOF> to signal the end of the message.
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];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// 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;
}
}
That's will be the best solution.

Threads can work fine but rarely scales well to that many clients. There are two easy ways and lots of more complex ways to handle that, here's some pseudocode for how the easier two are usually structured to give you an overview.
select()
This is a call to check which sockets have new clients or data waiting on them, a typical program looks something like this.
server = socket(), bind(), listen()
while(run)
status = select(server)
if has new client
newclient = server.accept()
handle add client
if has new data
read and handle data
Which means no threads are needed to handle multiple clients, but it doesn't really scale well either if handle data take a long time, then you won't read new data or accept new clients until that's done.
Async sockets
This is another way of handling sockets which is kind of abstracted above select. You just set up callbacks for common events and let the framework do the not-so-heavy lifting.
function handleNewClient() { do stuff and then beginReceive(handleNewData) }
function handleNewData() { do stuff and then beginReceive(handleNewData) }
server = create, bind, listen etc
server.beginAddNewClientHandler(handleNewClient)
server.start()
I think this should scale better if your data handling take a long time. What kind of data handling will you be doing?

This could be a good starting point. If you want to avoid 1 thread <-> 1 client; then you should use async socket facilities provided in .NET. Core object to use here is SocketAsyncEventArgs.

Related

How can we send the data using TcpListener in c#?

As per MSDN:
The TcpListener class provides simple methods that listen for and accept incoming connection requests in blocking synchronous mode.
My team lead is asking to send the data using TcpListener. Is there any way or feasible to receive as well as send the data using TCPListerner ?
I already know how to receive the data using TCPListener, don't have any idea about sending the data with the same. I know TCPClient can be used to send the data but our team lead wants to do it using TCPListerner.
Please let me know your comments and let me know if it is feasible with some sample code.
Not really. The purpose of TcpListener is to accept a new connection.
However, the stream object you get from your TcpListener (once the connection is established) can be used for reading and writing.
Look here for more details:
https://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener%28v=vs.110%29.aspx
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
class MyTcpListener
{
public static void Main()
{
TcpListener server=null;
try
{
// Set the TcpListener on port 13000.
Int32 port = 13000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
// Enter the listening loop.
while(true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while((i = stream.Read(bytes, 0, bytes.Length))!=0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
Console.WriteLine("Sent: {0}", data);
}
// Shutdown and end connection
client.Close();
}
}
catch(SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
}

Socket read freezes

I'm working on small program for learning purpose.
My program is simple Telnet console.
Using visual studio 2010 Express I created pretty cool UI now I'm trying to establish communication with remote server(Creston control processor). I copied and pasted class from this Microsoft article and when I execute the class the program freezes. I'm not sure how to properly describe what happens but in basic word all controls(including close button) stop working.
Here code for my class:(I added few debug lines);
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 string TempString = string.Empty;
public int TotalBytesRead = 0;
public char[] charBuffer = new char[1000];
}
public class AsynchronousClient
{
// The port number for the remote device.
private const int port = 23;
// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone =
new ManualResetEvent(false);
private static ManualResetEvent sendDone =
new ManualResetEvent(false);
private static ManualResetEvent receiveDone =
new ManualResetEvent(false);
// The response from the remote device.
private static String response = String.Empty;
public AsynchronousClient()
{
}
public void New()
{
StartClient();
}
private static void StartClient()
{
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// The name of the
// remote device is "host.contoso.com".
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("10.106.6.60"), port);
// Create a TCP/IP socket.
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
Console.WriteLine("StartSend");
// Send test data to the remote device.
//Send(client, "hostname\n");
//sendDone.WaitOne();
Console.WriteLine("WaitForResponse");
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
// Write the response to the console.
Console.WriteLine("Read From Socket : {0}", response);
Console.WriteLine("ReleaseSocket");
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Disconnect(true);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
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 Receive(Socket client)
{
try
{
// Create the state object.
Console.WriteLine("Receive");
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.
Console.WriteLine("Start Read");
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
Console.WriteLine("Bytes read: {0}", bytesRead);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
string tsTempString = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
state.TempString += tsTempString;
Console.WriteLine("String {0}", tsTempString);
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)
{
response = state.sb.ToString();
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Send(Socket client, String data)
{
Console.WriteLine("Send");
// 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, 0,
new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Console.WriteLine("SendCallBack");
// 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());
}
}
}
When connecting to the server it responds with following lines:
CP3 Console
Warning: Another console session is open
CP3>
When I run the program i get following output:
Socket connected to 10.106.6.60:23
StartSend
WaitForResponse
Receive
Start Read
Bytes read: 13
String CP3 Console
Start Read
Bytes read: 43
String Warning: Another console session is open
Start Read
Bytes read: 6
String
CP3>
The thread '<No Name>' (0x1d80) has exited with code 0 (0x0).
The thread '<No Name>' (0x24bc) has exited with code 0 (0x0).
I tried different methods of reading stream but no successes. The program still hangs up at the same spot.
It seems as after reading last byte ">" the program does not re-executes method "ReceiveCallback" to exit out of the loop.
I get feeling it has something with the way "ReceiveCallback" is being called but I could not figure out what client.beginReceive() parameters actually do.
To expand on Roemer's answer: EndReceive will return 0 only if the conversation has terminated. That usually means a TCP packet with the FIN or RST flag has been received, most often because the peer - in your case, the server - closed its endpoint or exited. (There are various other cases; for example, a firewall or intermediate node could generate an RST.)
(Roemer wrote "BeginReceive never returns zero...", but clearly meant EndReceive, since BeginReceive returns the IAsyncResult object.)
If the peer doesn't close its end of the conversation, EndReceive won't return 0, and you'll never enter the else branch of your callback that invokes receiveDone.Set().
It's not entirely clear from your description exactly how the server behaves, but its last send of 6 bytes was clearly a newline followed by the "CP3>" prompt. At that point it's waiting for your client to send something. It's not going to close the connection.
TCP is a bytestream service - it doesn't provide record boundaries. So there's no way for the socket layer to know when the server is "done sending", except when the server closes the connection. You have three choices for your client:
Parse the server's output as you receive it and recognize when it's waiting for input (in this case, that means recognizing the "CP3>" prompt)
Decide the server's done after some arbitrary time has passed with no further data from the server
Don't worry about it, and simply output data from the server as you receive it
That third option is the simplest one. Do your first BeginReceive after making the connection. Then, in your callback method, if the conversation is still open and no errors have occurred, process the data you've received and invoke BeginReceive again.
To be honest, this example from microsoft is really bad.
In general, client.EndReceive never returns 0 except when the connection is closed. So receiveDone.Set will never be called in your example. In a more real-live example, you should check the received data in ReceiveCallback and when a keyword (like "Login: ") occurs, set the receiveDone and start sending (the login data for example) and the start receiving again and so on. You might also want to look at the async/await keyword (.net 4.5) and maybe upgrade to Visual Studio community edition :)
There are tons of examples on codeproject or found via google (like http://blogs.msdn.com/b/pfxteam/archive/2011/12/15/10248293.aspx).

Multithreading: passing different custom control properties between threads (or using them asynchronously)

I'm trying to develop a project where I can have multiple clients making their own server requests for the purpose of stress testing. I'm having a lot of difficulty figuring out how I can manipulate custom control properties when I make a new thread and want that thread to do the work. I have upwards of 100 controls; so ideally 100 individual clients. The problem is my controls are part of the GUI and I don't know how to allow that thread in question get access from that relative control.
Here's what I have:
// Custom project.class to get access to a custom base of properties created within the tool itself.
List<custom_control_project.custom_control_widget> controlList = new List<custom_control_project.custom_control_widget>();
private async void btnStart_Click(object sender, EventArgs e)
{
...// control property initializations
foreach (var control in controlList)
{
if (control.Enabled)
{
Thread thread = new Thread(() => StartClient());
thread.Start();
// Loop until worker thread activates.
while (!thread.IsAlive);
... // Ideally the GUI updates would happen from these threads. Simple updates to labels based on status code responses and expected xml parameters received.
}
}
My StartClient() is largely based off Microsofts asynchronous socket client example here: http://msdn.microsoft.com/en-us/library/bew39x2a%28v=vs.110%29.aspx
I was running these clients asynchronously but the program was not my end result. I have made a few changes, including resetting the ManualResetEvents. However, when I run my application, all the controls still run one after the other, and I'd like them to be independent. Do I have the right approach by making new threads with the StartClient()?
Referencing microsofts example, the part I'm most interested in is the ReceiveCallback(IAsyncResult ar) method:
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();
}
// ManualResetEvent instances signal completion.
private ManualResetEvent connectDone =
new ManualResetEvent(false);
private ManualResetEvent sendDone =
new ManualResetEvent(false);
private ManualResetEvent receiveDone =
new ManualResetEvent(false);
// The response from the remote device.
private String response = String.Empty;
public void StartClient()
{
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// The name of the
// remote device is "host.contoso.com".
//IPHostEntry ipHostInfo = Dns.Resolve("host.contoso.com");
//IPAddress ipAddress = ipHostInfo.AddressList[0];
//IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// Create a TCP/IP socket.
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(asyncServerHolder, asyncPortHolder,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
// Send test data to the remote device.
Send(client, (Upload)); //POST HTTP string + xml parameters
sendDone.WaitOne();
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
// Write the response to the console.
//MessageBox.Show("Response received : " + response);
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Close();
// Reset all manual events for next instance.
connectDone.Reset();
sendDone.Reset();
receiveDone.Reset();
}
catch (Exception)
{
//MessageBox.Show(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);
//MessageBox.Show("Socket connected to " + client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
private 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)
{
//MessageBox.Show(e.ToString());
}
}
private 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)
{
response1 = state.sb.ToString();
///
///
/// **THIS IS WHERE I WANT ALL THE PROCESSING TO BE DONE**
/// **AFTER THE RESPONSE IS COMPLETE!!**
///
///
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
private 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, 0,
new AsyncCallback(SendCallback), client);
}
private 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);
//MessageBox.Show("Sent " + bytesSent + " bytes to server.");
// Signal that all bytes have been sent.
sendDone.Set();
}
catch (Exception)
{
//MessageBox.Show(e.ToString());
}
}
How am I able to get the relative control from my foreach statement passed into the method and then amend my GUI (invoking somehow?) based on the outcome? Also, is it even possible to make each client independent, and have multiple client to server to client requests simultaneously? That is my main objective.
If this is a far fetched or very discouraged way of attempting this, please say so. Without diving into too much programming jargon (for understanding purposes, I'm fairly new to programming), how would you go about doing this?
Thanks in advance!
Well, you can sort of manipulate any control from a different thread by using the BeginInvoke function on the control, passing the action you want to execute. The action will be executed on the UI thread.
But your main problem here is that you're failing to separate the concerns. You UI code can for sure make actions happen, but these actions should be distinct from any UI code. You should design your actions in such a way to make them reusable. In other words, if you decide to rewrite your UI from scratch, you should still be able to reuse your actions as-is.
To make this possible, your actions should not reference any UI, they even should not be aware of the existence of any UI. This will make your code more manageable. So extract all that stuff in a different class, and then use something like events for instance to communicate back with the UI. The UI code then would make the BeginInvoke call.

TCP server in C# causing 100% CPU usage after 2-3 days

Here's my code for a very simple TCP Server (basically the sample Asynchronous Server Socket example - http://goo.gl/Ix5C - modified slightly):
public static void InitiateListener()
{
try
{
allDone = new ManualResetEvent(false);
configFile = new XmlConfig();
StartListening();
}
catch (Exception exc)
{
LogsWriter f = new LogsWriter(configFile.ErrorLogsPath);
f.WriteToFile(exc.Message);
f.CloseFile();
}
}
private static void StartListening()
{
try
{
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, configFile.Port);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception exc)
{
throw exc;
}
}
public static void AcceptCallback(IAsyncResult ar)
{
allDone.Set(); // Signal the main thread to continue.
// 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 hexData = string.Empty;
// Retrieve the state object and the handler socket from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
try
{
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
hexData = BitConverter.ToString(state.buffer);
if (hexData.Contains("FA-F8")) //heartbeat - echo the data back to the client.
{
byte[] byteData = state.buffer.Take(bytesRead).ToArray();
handler.Send(byteData);
}
else if (hexData.Contains("0D-0A")) //message
{
state.AsciiData = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
state.ParseMessage(configFile);
}
}
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
catch (Exception)
{
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
This is all in a Windows service. And the CPU maxes to 100% after about 2 and a half days of running perfectly acceptably. This has happened 3 times now - the windows service always works fine and functions as it's supposed to, utlizing almost no CPU resources but sometime on the 3rd day goes to 100% and stays there until the service is resarted.
I get very simple CSV packets, that I parse quickly and send it off to a database via a webservice in this method:
state.ParseMessage(configFile);
Even when the CPU is 100%, the database gets filled up pretty reliably. But I understand this could be one place where I need to investigate?
Which other areas of the code seem like they could be causing the problem? I'm new to async programming, so I don't know if I need to close threads manually. Also, this might be another problem:
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
Calling that line within ReadCallback itself. I do this to maintain the connection with the client and continue to receive the data, but maybe I should close to the socket and force a new connection?
Could you please offer some suggestions? Thanks
Instead of loop while(true) in startlistening method we need to call
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
from AcceptCallback method once completion of accepting new client.
You need to detect disconnection through bytesRead == 0. Right now you don't and instead issue another read.
Looks like you have copied MSDN sample code. I can tell because of the insightless combination of async IO and events. All this code becomes simpler when you use synchronous IO.

Async Socket listener sending data error

I'm creating a wrapper class around the Socket class.
I have a connect async callback which does this:
public void StartConnecting()
{
// Connect to a remote device.
try
{
//_acceptIncomingData = acceptIncomingData;
// Create a TCP/IP socket.
_workingSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
if (Information != null)
Information(this, new InfoEventArgs("Connecting", "Working socket is initiating connection"));
// Connect to the remote endpoint.
_workingSocket.BeginConnect(_localEndPoint,
new AsyncCallback(ConnectCallback), _workingSocket);
}
catch (Exception ex)
{
if (Error != null)
Error(this, new ErrorEventArgs(ex.Message, ex));
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
// ACTION CONNECTED COMPLETE
if (Information != null)
Information(this, new InfoEventArgs("Connected", "Working socket has now connected"));
// Start Receiving on the socket
// 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 ex)
{
if (Error != null)
Error(this, new ErrorEventArgs(ex.Message, ex));
}
}
And for the state object it uses a predifined class:
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();
}
I use this to connect to a socket that has begun listening, I call this listening socket the Server and it uses the Socket class. The code above is a socket that I call the Client. When the Client connects the Server, the Client is now allowed to send data to the Server. However when I want to receive data sent from the Server I get the following error message:
A request to send or receive data was disallowed because the socket is
not connected and (when sending on the datagram socket using a sendto
call) no address was supplied.
What am I missing? or not doing correctly?
After being prompted to check whether the Server is listening I looked at what I call the WorkingSocket in my wrapper class which is the socket that is being used, I checked this out after I had a successful Server listen/Client connect negotiate. It does say the socket isn't connected. So my question now is:
Does a Server (listening socket) need to be connected to the Client to send data, how do you do this if you have one Server for many Clients?
I had a misunderstanding of how sockets worked back in January. The error was caused because i didn't understand that when a Client connects to a listening socket, the listening socket then creates a new socket object where all data sent and received from the client will link back to.
In my example above I should create and store a new socket for the client to act on, and use this to send and receive data on.

Categories

Resources