C# TcpClient not sending or reading 100% of data? - c#

Hey all. I'm writing a simple client/server application (just for the experience, networking is fairly new to me) where the client sends the server data and the server outputs it to a textbox. It all works fine, except for one small detail... It seems sometimes a connection is made, but the data isn't being sent or read (can't work out which) and thus nothing is being outputted in the textbox. Every time a connection is made a counter is incremented, same thing when a data block is received. When you compare the two, the number of connections is correct but the data counter is usually lower, sometimes by as much as half. Anyway, if anyone can give me some advice or point me in the right direction, it would be greatly appreciated!
Here's the code if you require it:
(SERVER_CODE)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Server
{
public partial class Form1 : Form
{
public int Connections = 0;
public int blocks = 0;
public int threads = 0;
public Thread MasterThread;
public TcpListener Master;
public volatile bool Run;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void StartMaster()
{
Master = new TcpListener(IPAddress.Any, 1986);
Master.Start();
MasterThread = new Thread(new ThreadStart(RunMaster));
MasterThread.Start();
}
public void RunMaster()
{
threads++;
label6.Text = String.Format("{0}", threads);
while (Run)
{
TcpClient client = Master.AcceptTcpClient();
Connections++;
label4.Text = String.Format("{0}", Connections);
Thread ClientThread = new Thread(new ParameterizedThreadStart(RunClient));
ClientThread.Start(client);
}
Master.Stop();
threads--;
label6.Text = String.Format("{0}", threads);
}
public void RunClient(object tcpClient)
{
TcpClient client = (TcpClient)tcpClient;
byte[] buffer = new byte[4096];
int byteCount = 0;
NetworkStream stream = client.GetStream();
threads++;
label6.Text = String.Format("{0}", threads);
while (Run)
{
try
{
byteCount = stream.Read(buffer, 0, 4096);
}
catch
{
//Connections--;
break;
}
if (byteCount == 0)
{
//Connections--;
break;
}
blocks++;
label5.Text = String.Format("{0}", blocks);
textBox1.AppendText(Encoding.ASCII.GetString(buffer, 0, byteCount) + "\r\n");
}
client.Close();
threads--;
label6.Text = String.Format("{0}", threads);
}
private void button1_Click(object sender, EventArgs e)
{
Run = true;
StartMaster();
}
private void button2_Click(object sender, EventArgs e)
{
Run = false;
}
}
}
(CLIENT_CODE)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Client
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1986);
TcpClient client = new TcpClient();
try
{
client.Connect(endPoint);
}
catch
{
MessageBox.Show("Connect Error");
}
NetworkStream stream = client.GetStream();
byte[] data = Encoding.ASCII.GetBytes(textBox1.Text);
stream.Write(data, 0, data.Length);
stream.Flush();
client.Close();
}
}
}
Thank-you,
Tristan!.

Well, to start with you're crippling your own diagnostics with this:
catch
{
//Connections--;
break;
}
Why are you swallowing exceptions without any logging etc? Maybe an exception is being thrown, and you have no way of knowing. Ideally you should catch specific exceptions, and when you do catch an exception at least log what's going on.
At the other end of the spectrum, Wireshark should help you to work out whether the data is being sent or not.

I haven't had a thorough look at your code yet, but after a quick glance, you access variables from multiple threads without proper locking. A statement like x++; has to read the value of x, increment it, and write it back. Now if you have two threads doing this, you might run into this situation:
x = 0
Thread 1 Thread 2
------------------------
Read (0)
Read (0)
Increment (1)
Increment (1)
Write (1)
Write (1)
=> x = 1 instead of 2
If you need to access variables from multiple threads, ALWAYS synchronize unless you know exactly what you're doing. For example, create and use a synchronization object like this:
int threads = 0;
object threadSync = new object();
...
lock (threadSync) {
threads++;
}
Then only one thread may access the variable at a time and values are incremented correctly.
Edit: Another problem is that you access visible controls from a different thread than the one that created them. Early .NET versions allowed this, but the newer don't. If you need to update status messages, you need to look at the control's InvokeRequired property and if set to true, use Control.Invoke(...) to call a method that sets the property.

Related

"How to establish TCP connection with multiple IPs from single client C# application"

I had developed a C# TCP Client application to connect multiple IPs simultaneously or concurrently. I had programmed my application in such a way that, application will create thread for each IP and establish connection with the same and after finishing its job, that particular thread will be killed. The same thing will happen for all threads. (For Eg. If my application needs to connect 100 IPs simultaneously, 100 threads will be created for each IP. Every thread will be killed once they are done with their job). I had mentioned my code for thread creation below. I just wanted to know whether I'm going in a right way. Is this way of my approach is good? Please guide me in this regard. Thanks in advance
for (int i = 0; i < IPsCount; i++)
{
try
{
Thread serverThread = new Thread(Service);
serverThread.Start(IP_Add);
System.Threading.Thread.Sleep(100);
}
catch (Exception ex)
{
ex.ToString();
}
}
Every thread will be killed in Service method after finishing their job.
I would store all IP-Adresses in a collecton and do
Paralell.ForEach. Should be easier and saves you all the bare-metall thread handling :-)
UPDATE after discussion in comments:
I understood the OP that each connection is used for a short period, that is query some data then close. Then my method is good.
For long running tasks do create threads on your own or go to a boss-worker modell.
You could do something like below.
This code is an untested attempt at using System.IO.Pipelines to achieve your goal.
It should be a much better starting point than using Thread.Start directly.
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO.Pipelines;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Program
{
private static readonly IEnumerable<IPEndPoint> ipAddresses = new[]
{
new IPEndPoint(IPAddress.Loopback, 8087),
// more here.
};
internal static async Task Main()
{
await Task.WhenAll((await Task.WhenAll(
ipAddresses.Select(OpenSocket)))
.SelectMany(p => p));
// Handling code in ProcessLine.
}
private static async Task<IEnumerable<Task>> OpenSocket(
EndPoint iPEndPoint)
{
var socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
await socket.ConnectAsync(iPEndPoint);
var pipe = new Pipe();
var attendants = new[]
{
FillPipeAsync(socket, pipe.Writer),
ReadPipeAsync(socket, pipe.Reader)
};
return attendants;
}
private static async Task FillPipeAsync(Socket socket, PipeWriter writer)
{
const int minimumBufferSize = 512;
while (true)
{
try
{
// Request a minimum of 512 bytes from the PipeWriter
var memory = writer.GetMemory(minimumBufferSize);
var bytesRead = await socket.ReceiveAsync(
memory,
SocketFlags.None);
if (bytesRead == 0)
{
break;
}
// Tell the PipeWriter how much was read
writer.Advance(bytesRead);
}
catch
{
break;
}
// Make the data available to the PipeReader
var result = await writer.FlushAsync();
if (result.IsCompleted)
{
break;
}
}
// Signal to the reader that we're done writing
writer.Complete();
}
private static async Task ReadPipeAsync(Socket socket, PipeReader reader)
{
while (true)
{
var result = await reader.ReadAsync();
var buffer = result.Buffer;
SequencePosition? position;
do
{
// Find the EOL
position = buffer.PositionOf((byte)'\n');
if (position == null)
{
continue;
}
var line = buffer.Slice(0, position.Value);
ProcessLine(socket, line);
// This is equivalent to position + 1
var next = buffer.GetPosition(1, position.Value);
// Skip what we've already processed including \n
buffer = buffer.Slice(next);
} while (position != null);
// We sliced the buffer until no more data could be processed
// Tell the PipeReader how much we consumed and how much we
// left to process
reader.AdvanceTo(buffer.Start, buffer.End);
if (result.IsCompleted)
{
break;
}
}
reader.Complete();
}
private static void ProcessLine(
Socket socket,
in ReadOnlySequence<byte> buffer)
{
Console.Write($"[{socket.RemoteEndPoint}]: ");
foreach (var segment in buffer)
{
Console.Write(Encoding.UTF8.GetString(segment.Span));
}
Console.WriteLine();
}
}
}

How can I create a button click handler?

I have a number of buttons which flicker at different frequencies in my Wondows Form Application. When a specific frequency is measured on the head by an electrode, the signal undergoes signalprocessing in MATLAB, hereafter the frequency found are sent to the application, where the specific value from the UDP connection should press the button which have this specific flickering frequency. I am a bit lost how to create this button handler, using the data I get from Matlab. My thought is:
Value from connection ->
if value == 6
{
button1 is clicked
}
elseif value == 6.5
{
button2 is clicked
}
and so forth.
Any ideas any one ?
if(returnData == String.Empty)
{
}
else
{
button2.PerformClick();
}
Here the returnData is the ongiong incomming data from the UDP connection to MATLAB, you this would work ?
And for another question, I am having a bit of trouble with UDP connection, I would like if it could receive the data I am sending, right now, I have to press a button to open and recieve data, I have made it like this, because I could not update the data otherwise. In mind, I am a novice to C#.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
namespace WindowsFormsApplication4
{
public partial class Form1 : Form
{
//public UdpClient receivingUdpClient = null;
public string returnData;
//public byte[] Receive(ref IPEndPoint remoteEP);
// private Print print = null;
//while (true)
//{
public UdpClient receivingUdpClient = new UdpClient(8051);
//bool done = false;
//Creates an IPEndPoint to record the IP Address and port number of the sender.
// The IPEndPoint will allow you to read datagrams sent from any source.
//while (true)
//{
public IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8051);
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
label1.Visible = false;
label2.Visible = false;
}
void button1_Click(object sender, EventArgs e)
{
label1.Visible = false;
try
{
//while (true)
//{
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = receivingUdpClient.Receive(ref RemoteIpEndPoint);
returnData = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine("This is the message you received " +
returnData.ToString());
Console.WriteLine("This message was sent from " +
RemoteIpEndPoint.Address.ToString() +
" on their port number " +
RemoteIpEndPoint.Port.ToString());
// }
}
catch (Exception err)
{
Console.WriteLine(err.ToString());
}
if(returnData == String.Empty)
{
}
else
{
button2.PerformClick();
}
}
void button2_Click(object sender, EventArgs e)
{
if (SPELL.Text == String.Empty)
{
SPELL.Text = SPELL.Text + returnData;
label1.Visible = true;
}
else
{
SPELL.Text = null;
SPELL.Text = SPELL.Text + returnData;
label1.Visible = true;
label2.Visible = true;
}
}
}
}
This is my small test program in VIsual Studio so far.
Thanks.
If you want to simulate a button click from code behind, you could simply call the button's handler wherever you want the call to be made.
E.g.
if (value == 6)
{
this.button1_click(this,new EventArgs()) //button1 is clicked
}
else if (value == 6.5)
{
this.button2_click(this,new EventArgs()) //button2 is clicked
}
I'd recommend you better move the button handler's logic to a separate method and call the method instead of calling the handler directly.

Serial port reading + Threads or something better?

I dont know if this is a good way to work with a stack for this task but I'm sure there is a faster way ...
I get data from my microcontroller but the data length is not always the same length.
I thought maybe I can push data in my stack and in a thread I can pop it and decode the message. I didnt wanted slow down the DataReceivedHandler so then I created a Thread which can pop the data and write it to my Listview in my decodeMessage() function.
After a short time I get a System.OutOfMemories Exception..
Any ideas how I can do it in a better way ?
I'm reading from my serial port just when data arrives here:
Stack<byte[]> stack = new Stack<byte[]>();
.....
public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
byte[] data = new byte[sp.BytesToRead];
sp.Read(data, 0, data.Length);
stack.Push(data);
}
And this is my Thread:
private void formatData()
{
try
{
while (true)
{
byte[] data;
int i=0;
Dispatcher.BeginInvoke(new Action(() =>
{
while (stack.Count > 0)
{
data = stack.Pop();
while (i < data.Length)
{
decodeMessage(data[i]);
i++;
}
}
}));
}
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
thx
This code use a thread safe queue. I simplified some of my own code, so this code is not tested or compiled. If you have problems compiling or it produce errors, add a comment to me and I will help you out.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Windows.Threading;
using System.Collections.Concurrent;
void someRoutine()
{
// initialize queue before using it
serialDataQueue = new ConcurrentQueue<char>();
}
/// <summary>
/// data from serialPort is added to the queue as individual chars,
/// a struct may be better
/// </summary>
public ConcurrentQueue<char> serialDataQueue;
// get data
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = sender as SerialPort;
int bytesAvailable = sp.BytesToRead;
// array to store the available data
char[] recBuf = new char[bytesAvailable];
try
{
// get the data
sp.Read(recBuf, 0, bytesAvailable);
// put data, char by char into a threadsafe FIFO queue
// a better aproach maybe is putting the data in a struct and enque the struct
for (int index = 0; index < bytesAvailable; index++)
serialDataQueue.Enqueue(recBuf[index]);
}
catch (TimeoutException ex)
{
// handle exeption here
}
}
/// <summary>
/// Check queue that contains serial data, call this
/// routine at intervals using a timer or button click
/// or raise an event when data is received
/// </summary>
private void readSearialDataQueue()
{
char ch;
try
{
while (serialDataQueue.TryDequeue(out ch))
{
// do something with ch, add it to a textbox
// for example to see that it actually works
textboxDataReceived.Text += ch;
}
}
catch (Exception ex)
{
// handle ex here
}
}

I need SerialPort event on NewLine received

I need event, that will call my function after full line received, not just one byte.
SerialPort object in .NET has 3 events: DataReceived, ErrorReceived, PinChanged.
When im using DataReceived - event is "firing" after 1 byte, or after "x" bytes defined in "ReceiveByteThreshold" property. Line length may vary, so i cant predict "x".
Can someone give me a hint?
I have to create some buffer, which will collect bytes until LF/CRLF, or there is better approach to problem?
You cannot get this, the only option is SerialPort.ReceivedBytesThreshold to delay the DataReceived event handler call and that's useless for a variable length response.
The workaround is very simple, just call ReadLine() in your DataReceived event handler. That will block on a worker thread, not affecting anything else going on in your program. No danger either of additional events firing while the ReadLine() call is blocking, it is interlocked inside the SerialPort class. Use the ReadTimeout property if necessary if the communication isn't reliable enough so ReadLine() will not block forever. Set it to ten times the expected delay in receiving the longest possible response.
You'll have to do it yourself. Use DataReceived and check each byte. Collect the bytes in a buffer until you get a newline and then handle the buffer as a line at that point.
The hint:
The SerialPort class has a property NewLine to set the value used to interpret the end of a call to the ReadLine method.
Here is my quickly implemented, non blocking, same thread solution. It is a very basic state machine that waits for '\r' and '\n' and then sends all the buffered characters for parsing. You can alter it to whatever line-break value you want by changing the state machine itself.
In this approach you can register for the OnNewLineReceived event and process the data from the SerialStringMessgae eventhandler.
No try/catch overhead. No deadlocks.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace NonBlockingSerialPortReadLine
{
public partial class Form1 : Form
{
System.IO.Ports.SerialPort sp = new System.IO.Ports.SerialPort();
public event EventHandler OnNewLineReceived;
System.Windows.Forms.Timer NewDataTimer = new System.Windows.Forms.Timer();
int StateMachine = 0;
StringBuilder stringBuffer = new StringBuilder();
public Form1()
{
InitializeComponent();
InitTimer();
InitOnNewLineReceived();
}
private void InitTimer()
{
NewDataTimer.Interval = 50;
NewDataTimer.Tick += NewDataTimer_Tick;
}
private void InitOnNewLineReceived()
{
OnNewLineReceived += Form1_OnNewLineReceived;
}
void Form1_OnNewLineReceived(object sender, EventArgs e)
{
SerialStringMessgae STM = e as SerialStringMessgae;
string messgae = STM.message;
// PARSE YOU MESSAGE HERE - the debug line below is not mandatory
System.Diagnostics.Debug.WriteLine(messgae);
}
class SerialStringMessgae : EventArgs
{
public string message;
}
private void StartListeningButton_Click(object sender, EventArgs e)
{
StartListeningButton.Enabled = false;
sp = new System.IO.Ports.SerialPort("COM4",57600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One);
try
{
sp.Open();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return;
}
if (sp.IsOpen)
{
NewDataTimer.Enabled = true;
}
}
void NewDataTimer_Tick(object sender, EventArgs e)
{
string newData = sp.ReadExisting();
foreach (char c in newData)
{
switch (StateMachine)
{
case 0:
// waiting for '\r'
if (c == '\r')
{
StateMachine = 1;
}
else
{
stringBuffer.Append(c);
}
break;
case 1:
// waiting for '\n'
if (c == '\n')
{
if (OnNewLineReceived != null)
{
SerialStringMessgae STM = new SerialStringMessgae();
STM.message = stringBuffer.ToString();
OnNewLineReceived(this, STM);
}
}
// after parsing the message we reset the state machine
stringBuffer = new StringBuilder();
StateMachine = 0;
break;
}
}
}
}
}

Is it bad Ju-ju that the port is still being listened to after my app shuts down?

My app listens on a certain port for socket messages. I can see that it is LISTENING via "netstat -a" at the command line.
When I shut the app down, the machine is still listening on that port when I re-run "netstat -a"
Is this a problem?
It seems like maybe it is, as when I subsequently start the app again, it crashes ignominiously.
How can I cause the listening to cease?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;
namespace testSocketSendAndReceive_Nutshell
{
public partial class Form1 : Form
{
string sJerrysIPAddr = "10.24.93.110";
string sMyIPAddr = "10.24.93.128";
string sThisAppFileName = string.Empty;
bool bThisInstanceFunctionsAsServer = false;
internal static Form1 MainSocketPairForm = null;
public Form1()
{
InitializeComponent();
MainSocketPairForm = this;
}
private void Form1_Load(object sender, EventArgs e)
{
sThisAppFileName = System.Diagnostics.Process.GetCurrentProcess().ProcessName; // This provides just the app name, appending ".vshost" but NOT ".exe" (testSocketSendAndReceive_Nutshell.vshost)
lblFileName.Text = sThisAppFileName;
// Client and Server code are here combined in one app; however, we want each instance to run as
// just one or the other, so (the .exe functioning as a Server should be renamed with the subString
// "Server" somewhere in the filename):
bThisInstanceFunctionsAsServer = sThisAppFileName.Contains("Server");
if (bThisInstanceFunctionsAsServer)
{
new Thread(Server).Start(); // Run server method concurrently.
Thread.Sleep(500); // Give server time to start.
}
btnSendMsg.Visible = !bThisInstanceFunctionsAsServer;
textBox1.Visible = !bThisInstanceFunctionsAsServer;
}
static void Client()
{
using (TcpClient client = new TcpClient(Form1.MainSocketPairForm.sJerrysIPAddr, 51111)) // err here second time around
using (NetworkStream n = client.GetStream())
{
BinaryWriter w = new BinaryWriter(n);
w.Write(Form1.MainSocketPairForm.textBox1.Text.ToString());
w.Flush();
Form1.MainSocketPairForm.label1.Text = new BinaryReader(n).ReadString();
}
}
static void Server()
{
TcpListener listener = new TcpListener(IPAddress.Any, 51111);
listener.Start();
var shouldExit = false;
while (!shouldExit)
using (TcpClient c = listener.AcceptTcpClient())
{
using (NetworkStream n = c.GetStream())
{
string msg = new BinaryReader(n).ReadString();
if (msg == "exit")
// Client told us to exit...
shouldExit = true;
BinaryWriter w = new BinaryWriter(n);
w.Write(msg + " back atcha!");
w.Flush(); // Must call Flush because we're not disposing the writer.
}
}
}
private void button1_Click(object sender, EventArgs e)
{
Client();
}
private void button2_Click(object sender, EventArgs e)
{
Close();
}
}
}
Your application is probably not actually exiting (check task manager "Processes" tab for your .exe).
You are probably trying to close the application by just closing the command window. Because your Server thread is not a background thread, it will just keep running. Try this guy in Form_Load:
if (bThisInstanceFunctionsAsServer)
{
var serverThread = new Thread(Server);
serverThread.IsBackground = true; // Make sure the server thread doesn't keep the app running in the background
serverThread.Start(); // Run server method concurrently.
Thread.Sleep(500); // Give server time to start.
}

Categories