TcpListener.AcceptSocket produce InvalidOperationException - c#

I'm not to acquainted with TcpListener and sockets, but I have the following code that execute correctly sometimes in my Initializer class from my App_Code of my Wcf project, but then the first correct execute it show me errors sometimes and then execute correctly other ones without pattern.
The error stop in this line code:
Socket soc = listener.AcceptSocket();
And then shows this aditional information:
Additional Information: Not in Listening. Call the Start () method before calling this method.
But like you can see I call start method before listener.AcceptSocket()…
I suspect that this is for try to begin a init daemon in a WCF project.
public static void AppInitialize()
{
// This will get called on startup
new Initializer().StartListener();
}
static TcpListener listener;
const int LIMIT = 5; //5 concurrent clients
private void StartListener()
{
List<int> puertos = new List<int>();
puertos.Add(5494);
puertos.Add(5495);
puertos.Add(5496);
puertos.Add(5497);
foreach (int puerto in puertos)
{
IPAddress localAddr = IPAddress.Parse(ConfigurationManager.AppSettings["ServerIP"]);
listener = new TcpListener(localAddr, puerto);
listener.Start();
for (int i = 0; i < LIMIT; i++)
{
Thread t = new Thread(new ThreadStart(Service));
t.Start();
}
}
}
private void Service()
{
while (true)
{
//Error happen hear, but listener.Start execute before... .
Socket soc = listener.AcceptSocket();
try
{
byte[] resp = new byte[2000];
var memStream = new MemoryStream();
var bytes = 0;
NetworkStream s = new NetworkStream(soc);
StreamReader sr = new StreamReader(s);
while (true)
{
string trama = "";
if (s.CanRead)
{
do
{
bytes = s.Read(resp, 0, resp.Length);
trama = Util.Util.ByteArrayToHexString(resp);
}
while (s.DataAvailable);
}
if (trama == "" || trama == null) break;
}
s.Close();
}
catch (Exception e)
{
}
finally
{
soc.Close();
}
}
}

Well, it's not clear why if this is a WCF program, you are using Socket or TcpListener directly. The point of WCF is to let it handle the network I/O for you.
That said…
You are getting the exception because the listener field is shared between all of your threads and one or more of your threads has managed to get to AcceptSocket() just after the first thread has created a new TcpListener object, but before it's called Start().
It's actually good you got the exception. Your code could easily have run without that exception, if you were unlucky enough, and then you'd have a much harder problem to debug because the only symptom would be that, mysteriously, not all of your listeners were accepting any clients.
IMHO, it would be best to design the code, such that you have separate object instances handling each listening socket (and use non-static members for values). That way, you can be sure each listener is operating correctly and independently.
But, the code you have here can be fixed, at least with respect to the exception, by passing the correct TcpListener object to each thread:
private void StartListener()
{
List<int> puertos = new List<int>();
puertos.Add(5494);
puertos.Add(5495);
puertos.Add(5496);
puertos.Add(5497);
foreach (int puerto in puertos)
{
IPAddress localAddr = IPAddress.Parse(ConfigurationManager.AppSettings["ServerIP"]);
TcpListener listener = new TcpListener(localAddr, puerto);
listener.Start();
for (int i = 0; i < LIMIT; i++)
{
Thread t = new Thread(() => Service(listener));
t.Start();
}
}
}
private void Service(TcpListener listener)
{
while (true)
{
Socket soc = listener.AcceptSocket();
try
{
byte[] resp = new byte[2000];
var memStream = new MemoryStream();
var bytes = 0;
NetworkStream s = new NetworkStream(soc);
StreamReader sr = new StreamReader(s);
while (true)
{
string trama = "";
if (s.CanRead)
{
do
{
bytes = s.Read(resp, 0, resp.Length);
trama = Util.Util.ByteArrayToHexString(resp);
}
while (s.DataAvailable);
}
if (trama == "" || trama == null) break;
}
s.Close();
}
catch (Exception e) { }
finally
{
soc.Close();
}
}
}
Be sure to remove the static TcpListener listener; field.
One last note: you should never catch Exception, except in a part of the code where all that will happen is that, optionally the exception is logged, and the process is terminated.

Related

create a TCP socket server which is able to handle thousands of requests per second

At the fist try, I created a basic TCP server as flowing:
public class Tcp
{
private TcpListener listener { get; set; }
private bool accept { get; set; } = false;
public void StartServer(string ip, int port)
{
IPAddress address = IPAddress.Parse(ip);
listener = new TcpListener(address, port);
listener.Start();
accept = true;
StartListener();
Console.WriteLine($"Server started. Listening to TCP clients at {ip}:{port}");
}
public async void StartListener() //non blocking listener
{
listener.Start();
while (true)
{
try
{
TcpClient client = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
HandleClient(client);
}
finally { }
}
}
private void HandleClient(TcpClient client)
{
try
{
NetworkStream networkStream = client.GetStream();
byte[] bytesFrom = new byte[20];
networkStream.Read(bytesFrom, 0, 20);
string dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
string serverResponse = "Received!";
Byte[] sendBytes = Encoding.ASCII.GetBytes(serverResponse);
networkStream.Write(sendBytes, 0, sendBytes.Length);
networkStream.Flush();
}
catch(Exception ex)
{
}
}
}
I wrote a client test code that is sending and recording number of requests per second
public class Program
{
private volatile static Dictionary<int, int> connections = new Dictionary<int, int>();
private volatile static int fail = 0;
private static string message = "";
public static void Main(string[] args)
{
ServicePointManager.DefaultConnectionLimit = 1000000;
ServicePointManager.Expect100Continue = false;
for (int i = 0; i < 512; i++)
{
message += "T";
}
int taskCount = 10;
int requestsCount = 1000;
var taskList = new List<Task>();
int seconds = 0;
Console.WriteLine($"start : {DateTime.Now.ToString("mm:ss")} ");
for (int i = 0; i < taskCount; i++)
{
taskList.Add(Task.Factory.StartNew(() =>
{
for (int j = 0; j < requestsCount; j++)
{
Send();
}
}));
}
Console.WriteLine($"threads stablished : {DateTime.Now.ToString("mm: ss")}");
while (taskList.Any(t => !t.IsCompleted)) { Thread.Sleep(5000); }
Console.WriteLine($"Compelete : {DateTime.Now.ToString("mm: ss")}");
int total = 0;
foreach (KeyValuePair<int, int> keyValuePair in connections)
{
Console.WriteLine($"{keyValuePair.Key}:{keyValuePair.Value}");
total += keyValuePair.Value;
seconds++;
}
Console.WriteLine($"succeded:{total}\tfail:{fail}\tseconds:{seconds}");
Console.WriteLine($"End : {DateTime.Now.ToString("mm: ss")}");
Console.ReadKey();
}
private static void Send()
{
try
{
TcpClient tcpclnt = new TcpClient();
tcpclnt.ConnectAsync("192.168.1.21", 5678).Wait();
String str = message;
Stream stm = tcpclnt.GetStream();
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(str);
stm.Write(ba, 0, ba.Length);
byte[] bb = new byte[100];
int k = stm.Read(bb, 0, 100);
tcpclnt.Close();
lock (connections)
{
int key = int.Parse(DateTime.Now.ToString("hhmmss"));
if (!connections.ContainsKey(key))
{
connections.Add(key, 0);
}
connections[key] = connections[key] + 1;
}
}
catch (Exception e)
{
lock (connections)
{
fail += 1;
}
}
}
}
when I test it on a local machine, I get the maximum number of 4000 requests per second and when I upload it to local Lan it decreases to 200 requests per second.
The question is:
how can I improve the server performance?
what is the correct way of load testing socket servers?
You may have a "non-blocking listener", but when any particular client connects, it devotes itself to just that client until that client has sent a message and a response has been sent back to it. That's not going to scale well.
I'm usually not a fan of async void, but it's in keeping with your current code:
public async void StartListener() //non blocking listener
{
listener.Start();
while (true)
{
TcpClient client = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
HandleClient(client);
}
}
private async void HandleClient(TcpClient client)
{
NetworkStream networkStream = client.GetStream();
byte[] bytesFrom = new byte[20];
int totalRead = 0;
while(totalRead<20)
{
totalRead += await networkStream.ReadAsync(bytesFrom, totalRead, 20-totalRead).ConfigureAwait(false);
}
string dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
string serverResponse = "Received!";
Byte[] sendBytes = Encoding.ASCII.GetBytes(serverResponse);
await networkStream.WriteAsync(sendBytes, 0, sendBytes.Length).ConfigureAwait(false);
networkStream.Flush(); /* Not sure necessary */
}
I've also fixed the bug I mentioned in the comments about ignoring the return value from Read and removed the "hide errors from me making bugs impossible to spot in the wild" error handling.
If you're not guaranteed that your clients will always send a 20 byte message to this code, then you need to do something else so that the server knows how much data to read. This is usually done by either prefixing the message with its length or using some form of sentinel value to indicate the end. Note that even with length-prefixing, you're not guaranteed to read the whole length in one go and so you'd need to also use a read loop, as above, to discover the length first.
If switching everything to async isn't giving you the scale you need, then you need to abandon using NetworkStream and start working at the Socket level, and specifically with the async methods designed to work with SocketAsyncEventArgs:
The SocketAsyncEventArgs class is part of a set of enhancements to the System.Net.Sockets.Socket class that provide an alternative asynchronous pattern that can be used by specialized high-performance socket applications... An application can use the enhanced asynchronous pattern exclusively or only in targeted hot areas (for example, when receiving large amounts of data).
The main feature of these enhancements is the avoidance of the repeated allocation and synchronization of objects during high-volume asynchronous socket I/O...
In the new System.Net.Sockets.Socket class enhancements, asynchronous socket operations are described by reusable SocketAsyncEventArgs objects allocated and maintained by the application...

C#.net Windows Service - how to log TCP port activities in a file?

How can I log port activities in C#.net WindowsService? Also, are there any issues with the following code? Socket programming is entirely new to me. I cant even log it.
public void Start()
{
try
{
// Read server IPAddress and port details from the config
string serverIP, serverPort;
serverIP = ConfigurationManager.AppSettings["ServerIP"];
serverPort = ConfigurationManager.AppSettings["ServerPort"];
// Initialize server IPAddress and port number
IPAddress serverIPAddress = IPAddress.Parse(serverIP);
int serverPortNumber = int.Parse(serverPort);
this.tcpListnr = new TcpListener(serverIPAddress, serverPortNumber);
this.tcpListnr.Start();
// Start listener thread
this.tcpListnrThread = new Thread(this.ThreadProc);
this.tcpListnrThread.Start();
}
catch (Exception ex)
{
if (Er != null)
this.Er.LogError(ex,"Error in Start ");
}
}
private void ThreadProc()
{
try
{
// Listen infinitly
while (true)
{
// Waiting for a connection
TcpClient tcpClient = this.tcpListnr.AcceptTcpClient();
// Connected
if (this.tcpListnrThread.IsAlive)
{
try
{
Thread readDataThread = new Thread(this.ReadDataThreadProc);// Read data in a separate thread
readDataThread.Start(tcpClient);
}
catch(Exception ex)
{
this.Er.LogError(ex,"Thread Abort");
}
}
}
}
catch (Exception ex)
{
if (Er != null)
this.Er.LogError(ex,"Error in ThreadProc - " );
}
}
Here is the example. Note that there is no error checks, no check if there is more data in the stream and etc. But this could help you start.
// Bind ip and port
TcpListener listener = new TcpListener(new IPAddress(new byte[] { 127, 0, 0, 1 }), 12345);
// start listener
listener.Start();
// endless cycle
while (true)
{
// acept client
TcpClient client = listener.AcceptTcpClient();
// using bgworker instead of thread, i like it more :D
using (BackgroundWorker bw = new BackgroundWorker())
{
// sign for dowork
bw.DoWork += Bw_DoWork;
// run worker and passing TcpClient as argument
bw.RunWorkerAsync(client);
}
}
And the data process part
// this will execute every time in separate thread
// when listener accept connection
private static void Bw_DoWork(object sender, DoWorkEventArgs e)
{
TcpClient client = (TcpClient)e.Argument;
// set read buffer length
int inBuffLen = 1024;
// declare input buffer
byte[] inBuff = new byte[inBuffLen];
// we will use network stream to read
NetworkStream stream = client.GetStream();
// real data length
int rlen;
// read from stream 1024 bytes of data and
// in rlen we've got a REAL amount of data bytes
rlen = stream.Read(inBuff, 0, inBuffLen);
// declare data array
byte[] data = new byte[rlen];
// copy from source array to data array
Array.Copy(inBuff, data, rlen);
// now you can do with data whatever you want
var s = "";
for (int i = 0; i < data.Length; i++)
s += string.Format("{0:X2}", data[i]);
Debug.WriteLine(s);
}

TCP Listener - Not updating a received data

This is my first TCP listener program,
I could receive, parse and display data successfully from another PC.
But can you please check why this listener is not receiving another data ?
I want to update it everytime time when a client sends data. But its not updating once received data.
Here is my code:
public partial class FeederControlMonitor : Form
{
public string Status = string.Empty;
public Thread T = null;
public FeederControlMonitor()
{
InitializeComponent();
}
private void FeederControlMonitor_Load(object sender, EventArgs e)
{
label1.Text = "Server is Running...";
ThreadStart Ts = new ThreadStart(StartReceiving);
T = new Thread(Ts);
T.Start();
}
public void StartReceiving()
{
ReceiveTCP(9100);
}
public void ReceiveTCP(int portN)
{
TcpListener Listener = null;
try
{
Listener = new TcpListener(IPAddress.Any, portN);
Listener.Start();
}
catch (Exception ex)
{
File.WriteAllText(#"C:\\Drive\\ex.txt", ex.Message);
Console.WriteLine(ex.Message);
}
try
{
Socket client = Listener.AcceptSocket();
byte[] data = new byte[10000];
int size = client.Receive(data);
while (true)
{
client.Close();
ParseData(System.Text.Encoding.Default.GetString(data));
}
Listener.Stop();
}
catch (Exception ex)
{
File.WriteAllText(#"C:\\Drive\\ex.txt", ex.Message);
}
}
public void ParseData(string data)
{
var useFulData = data.Substring(data.IndexOf("F1")).Replace(" ", "");
useFulData = useFulData.Remove(useFulData.IndexOf("<ETX>"));
string[] delimeters = { "<DEL>", "<ESC>" };
var listOfValues = useFulData.Split(delimeters, StringSplitOptions.None).ToList();
int pos = 0;
for (int i = 1; i < listOfValues.Count; i += 2, pos++)
{
listOfValues[pos] = listOfValues[i];
}
listOfValues.RemoveRange(pos, listOfValues.Count - pos);
txtTubeName.Text = listOfValues[0];
txtCID.Text = listOfValues[1];
txtLocation.Text = listOfValues[2];
txtGender.Text = listOfValues[3];
txtAge.Text = listOfValues[4];
}
private void btnExit_Click(object sender, EventArgs e)
{
T.Abort();
this.Close();
}
}
Thanks in advance.
To much to explain where are errors. Here is simple multithread TcpServer.
// Initialize listener.
IPAddress address = new IPAddress(new byte[] { 127, 0, 0, 1 });
TcpClient client;
// Bind to address and port.
TcpListener listener = new TcpListener(address, 12345);
// Start listener.
listener.Start();
// In endless cycle accepting incoming connections.
// Actually here must be something like while(_keepWork)
// and on some button code to make _keepWork = false to
// stop listening.
while (true)
{
client = listener.AcceptTcpClient();
// When client connected, starting BgWorker
// use "using" statement to automatically free objects after work.
using (BackgroundWorker bgWorker = new BackgroundWorker())
{
// EventHandler.
bgWorker.DoWork += BgWorker_DoWork;
// Past client as argument.
bgWorker.RunWorkerAsync(client);
}
}
And method to handle connection (Edit: with read data part):
private static void BgWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Get argument as TcpClient.
TcpClient client = e.Argument as TcpClient;
// Get stream from client.
NetworkStream netStream = client.GetStream();
// Input buffer to read from stream.
int inBuffSize = 1024;
byte[] inBuff = new byte[inBuffSize];
// Temporary buffer.
byte[] tempBuff;
// Result data recieved from client.
List<byte> data = new List<byte>();
// Read bytes from client into inputbuffer
int dataSize = netStream.Read(inBuff, 0, inBuffSize);
// If data recieved add to result.
while (dataSize > 0)
{
// Create new buffer.
tempBuff = new byte[dataSize];
// Copy data from inputBuffer to tempBuffer.
Array.Copy(inBuff, tempBuff, dataSize);
// Add to result.
data.AddRange(tempBuff);
// Read once more to check if any data still could be recieved.
dataSize = netStream.Read(inBuff, 0, inBuffSize);
}
}

C# socket read buffer error with multiple clients connecting to servers

I write an Windows C# application which can create up to 16 threads. Each thread creates a socket for a remote device. Each thread send commands to read the device status. (every 300 ms) It is OK when I create one or two threads to read the status. But when I create 10 threads to read device status, I will get wrong data in the socket receive buffer.
Please refer to the following for my socket driver code:
class SocketClient {
private IPAddress ipAddress;
private IPEndPoint remoteEP;
private Socket mSocket;
private SocketAsyncEventArgs e = new SocketAsyncEventArgs();
private System.Timers.Timer timer_connection;
private static byte[] response = new byte[1024];
private Boolean waittingConnectDone;
private Boolean boolConnected;
public SocketClient() {
}
private byte[] acknowledge = null;
public Boolean Connect(String IP, int Port) {
Boolean bRet = true;
ipAddress = IPAddress.Parse(IP);
remoteEP = new IPEndPoint(ipAddress, Port);
mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//mSocket.ReceiveTimeout = GlobalVar.ethernet_timeout;
mSocket.ReceiveTimeout = 500;
try {
waittingConnectDone = false;
e.RemoteEndPoint = remoteEP;
e.UserToken = mSocket;
e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed);
mSocket.ConnectAsync(e);
if (timer_connection != null) {
timer_connection.Dispose();
} else {
timer_connection = new System.Timers.Timer();
}
timer_connection.Interval = 2000;
timer_connection.Elapsed += new ElapsedEventHandler(timer_connection_Tick);
timer_connection.Start();
while (true) {
if (waittingConnectDone)
break;
Application.DoEvents();
}
bRet = boolConnected;
//sender.Connect(remoteEP);
} catch {
Debug.WriteLine("### Ethernet ### Connection Error!");
bRet = false;
}
return bRet;
}
private void e_Completed(object sender, SocketAsyncEventArgs e) {
boolConnected = true;
waittingConnectDone = true;
}
private void timer_connection_Tick(object sender, EventArgs e) {
if (!mSocket.Connected) {
timer_connection.Stop();
boolConnected = false;
waittingConnectDone = true;
}
}
public void Disconnect() {
try {
mSocket.Shutdown(SocketShutdown.Both);
mSocket.Close();
} catch {
}
}
Each Thread use following code to read the device status:
private byte[] acknowledge = null;
private static byte[] response = new byte[1024];
public byte[] sendCommand(byte[] Cmp_TxData) {
try {
bytesSent = mSocket.Send(Cmp_TxData);
bytesRec = mSocket.Receive(response);
acknowledge = new byte[bytesRec];
Array.Copy(response, 0, acknowledge, 0, bytesRec);
}
catch
{
acknowledge = null;
}
return acknowledge;
}
And the buffer data error is something like following:
TX --> 00-03-01-F4-00-03-44-14
RX <-- 00-00-00-00-00-00-00-00-00-00-00
Sometime I read correct data, but sometimes the data are all 0!
Is there anything wrong with my socket driver?
Really appreciate your help!!
I have not checked all of the posted code (I suspect there may be more errors, multithreading is hard if you try to do it all yourself), but this line:
private static byte[] response = new byte[1024];
Is definitely a source for the types of errors you report. This line declares a buffer that is shared between all threads.
So if multiple threads do this:
bytesRec = mSocket.Receive(response);
The data in this response buffer can be concurrently modified.
To resolve this specific error, you could ensure that you create a static buffer for each thread using [ThreadStatic] or ThreadLocal (see for example http://reedcopsey.com/2009/11/12/thread-specific-data-becomes-easier-in-net-4-0-via-threadlocalt/).

Server refuses to accept requests from clients

This is a program to search for strings from a file. The string required by the client is given from the client side, in my case, using telnet. The program I have written is a server side one. It accepts multiple clients.
But, the problems I am unable rectify are-
It doesn't check for strings from the file.
As soon as the client gets connected, the client cannot type in the strings they want to search in that particular file.
It doesn't send the reply back (i.e. If the string is present in the file or not) to the client. Its only shown on the server side.
How do I proceed further? Could someone tell me where am I going wrong? Could someone please help me out with the code?
This is my try at the program..
class Program
{
static void Main(string[] args)
{
IPAddress ipad = IPAddress.Parse("192.168.0.181");
TcpListener serversocket = new TcpListener(ipad, 8888);
TcpClient clientsocket = default(TcpClient);
Byte[] bytes = new Byte[256];
serversocket.Start();
Console.WriteLine(">> Server Started");
while(true)
{
clientsocket = serversocket.AcceptTcpClient();
Console.WriteLine("Accepted Connection From Client");
LineMatcher lm = new LineMatcher(clientsocket);
Thread thread = new Thread(new ThreadStart(lm.Run));
thread.Start();
Console.WriteLine("Client connected");
}
Console.WriteLine(" >> exit");
Console.ReadLine();
clientsocket.Close();
serversocket.Stop();
}
}
public class LineMatcher //I've jumbled it up here. Don't know what exactly to do..
{
public string fileName = "c:/myfile2.txt";
private TcpClient _client;
public LineMatcher(TcpClient client)
{
_client = client;
}
public void Run()
{
try
{
StreamReader sr = new StreamReader("c:/myfile2.txt");
using (var reader = new StreamReader(_client.GetStream()))
{
string line ="";
int lineNumber = 0;
while (null != (line = sr.ReadLine()))
{
lineNumber += 1;
byte[] data = new byte[1024];
NetworkStream stream = _client.GetStream();
//if (line.Equals(line))
for (int ct = stream.Read(data,0, data.Length-1); 0 < ct; ct = stream.Read(data,0,data.Length-1))
line += Encoding.ASCII.GetString(data, 0, ct);
line = line.Trim();
{
lineNumber.ToString();
data = Encoding.ASCII.GetBytes(line);
_client.Client.Send(data, data.Length, SocketFlags.None);
Console.WriteLine("Line {0} matches {1}", lineNumber, line);
}
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
Console.WriteLine("Closing client");
_client.Close();
}
}
I think you got some pieces in your Run-method swapped - here is a version that should do the job:
public void Run()
{
byte[] data;
try
{
using (var r = new StreamReader("c:/myfile2.txt"))
{
string line ="";
int lineNumber = 0;
while (null != (line = r.ReadLine()))
{
data = Encoding.ASCII.GetBytes(line + "\n");
_client.Client.Send(data, data.Length, SocketFlags.None);
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
Console.WriteLine("Closing client");
_client.Close();
}
Please note that I'm not 100% sure what you are trying to do (I think you want your textfile send line-by-line to your Terminal) - so you might have to change some bits here and there.
Don't know where the Stream-messes in your code came from but I guess you tried various tutorials/snippets and forgot to clean up ;)

Categories