I need SerialPort event on NewLine received - c#

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;
}
}
}
}
}

Related

How to handle DataReceived

Please see my code below, that I am trying to return back to method that I registered the port's DataReceived event. Basically, If I recieve data from port before read time out. I will return back where I registered DataReceived event and degister and continue process. I am trying to do it with while loop. But not sure if it is accurate, and it is the way that has to be done
or if there is any other way to do this.
public class CommClass{
private static byte[] portReturn = null;
private void setUpDevice()
{
byte[] command = { 0x11,0X51 };
try
{
port.DataReceived += new SerialDataReceivedEventHandler(serialPortDataReceived);
port.Write(command, 0, command.Length);
while (portReturn == null) { } //Not sure if this will work. If I receive data before times out I do not want to wait in the loop.
port.DataReceived -= serialPortDataReceived;
}
catch(Exception ex)
{
//to do
}
}
private void serialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
var servicePort = (SerialPort)sender;
portReturn = servicePort.ReadByte();
return;
}
}
You code will technically work; however, your while loop will max out your CPU while you're waiting for data to come in, which is not what you want. I recommend using a ManualResetEvent here to let you wait to receive data in a CPU friendly way. You can read more about them here
public class CommClass
{
private static byte[] portReturn = null;
// ManualResetEvents are great for signaling events across threads
private static ManualResetEvent dataReceivedEvent = new ManualResetEvent(false);
private void setUpDevice()
{
byte[] command = { 0x11,0X51 };
try
{
port.DataReceived += new SerialDataReceivedEventHandler(serialPortDataReceived);
port.Write(command, 0, command.Length);
// Wait for the event to be set without spinning in a loop.
// Can also specify a timeout period to wait in case the data never comes.
dataReceivedEvent.WaitOne();
// Reset the event so that you can use it again later if necessary
dataReceivedEvent.Reset();
port.DataReceived -= serialPortDataReceived;
}
catch(Exception ex)
{
//to do
}
}
private void serialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
var servicePort = (SerialPort)sender;
portReturn = servicePort.ReadByte();
// Set the event to let the main thread know you have received data
dataReceivedEvent.Set();
}
}

Form doesn't load in while loop

I have a class defined to get live capture from a camera, and a form button "END CAPTURE" that should halt the capture; and an typical Application.Exit() button.
However, for some reason the while loop as shown below doesn't load the form even when the condition is met. To debug this, I commented out the while loop to see if it snaps at least 1 image; and it does (as shown in fig). What makes the while loop not to load the form and show the output continuously ?
while (!terminated)
{
// CAMERA ACQUISITION CODE
}
Figure of single while loop run:
Full program for reference:
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.Threading;
using mv.impact.acquire;
using mv.impact.acquire.examples.helper;
namespace mv_BlueFoxControl
{
public partial class Form1 : Form
{
private bool button1WasClicked = false;
public Bitmap SnappedBitmap = null;
public static Image PersistentImage = null;
public Form1()
{
InitializeComponent();
mv.impact.acquire.LibraryPath.init(); // this will add the folders containing unmanaged libraries to the PATH variable.
Device pDev = DeviceManager.getDevice(0);// Get a pointer to the first device found
if (pDev == null)
{
Console.WriteLine("Unable to continue! No device found! Press any key to end the program.");
//Console.Read();
Environment.Exit(1);
}
Console.WriteLine("Initialising the device. This might take some time...");
try
{
pDev.open();//start the sensor
Console.WriteLine("Device opened successfully...");
}
catch (ImpactAcquireException e)
{
// throw error code if the same device is already opened in another process...
Console.WriteLine("An error occurred while opening the device " + pDev.serial +
"(error code: " + e.Message + "). Press any key to end the application...");
//Console.ReadLine();
Environment.Exit(1);
}
bool terminated = false;// Bool terminated was here.
Console.WriteLine("Press CAPTURE to end the application");
// create thread for live capture
Thread thread = new Thread(delegate()//Start live acquisition
{
DeviceAccess.manuallyStartAcquisitionIfNeeded(pDev, fi);
Request pRequest = null;
// we always have to keep at least 2 images as the display module might want to repaint the image, thus we
// can free it unless we have a assigned the display to a new buffer.
Request pPreviousRequest = null;
int timeout_ms = 500;
int cnt = 0;
int requestNr = Device.INVALID_ID;
Console.WriteLine(terminated);
while (!terminated)
{
// CAMERA ACQUISITON CODE
}
DeviceAccess.manuallyStopAcquisitionIfNeeded(pDev, fi);
// free the last potential locked request
if (pRequest != null)
{
pRequest.unlock();
}
// clear the request queue
fi.imageRequestReset(0, 0);
// extract and unlock all requests that are now returned as 'aborted'
requestNr = Device.INVALID_ID;
while ((requestNr = fi.imageRequestWaitFor(0)) >= 0)
{
pRequest = fi.getRequest(requestNr);
Console.WriteLine("Request {0} did return with status {1}", requestNr, pRequest.requestResult.readS());
pRequest.unlock();
}
});//End of thread
Console.WriteLine(" End Thread");
thread.Start();
if (button1WasClicked)
{
terminated = true;
}
Console.WriteLine("Program termination");
Console.WriteLine(terminated);
thread.Join();
}
private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void button1_Click(object sender, EventArgs e)
{
button1WasClicked = true;
}
}
}
Because of thread.Join(); The application will wait that the thread ends (which will not end until you press the button) and so the constructor is never finished.
You have to initialize a Thread field and only close it when you press the button.
Try this:
public partial class Form1 : Form
{
//...
private Thread _cameraThread;
public Form1()
{
//... the previous code
_cameraThread = new Thread(delegate()//Start live acquisition
{
// thread logic
});
_cameraThread.Start();
}
private void button2_Click(object sender, EventArgs e)
{
Application.Exit();
}
private void button1_Click(object sender, EventArgs e)
{
button1WasClicked = true;
//set the flag and wait for the thread to finish
_cameraThread.Join();
Console.WriteLine("Program termination");
}
}

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
}
}

C# Serial Communication to Arduino

I'm working on a project that involves my client software sending data to a Arduino microcontroller, AtMega32U4, through serial communication. I've looked through many answered questions so far yet none of them were specific to my problem. However, I believe my problem may be limited to threading issues or Arduino autoreset problems.
Code 1:
public MainForm()
{
InitializeComponent();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
serialPort1.DtrEnable = true;
//serialPort1.RtsEnable = true;
}
private void button3_Click(object sender, EventArgs e)
{
// Disables button while processing
button3.Enabled = false;
GetDir dir = new App.GetDir();
dir.getCoords(Origin.Text, Destination.Text, Application.StartupPath + #"\temp2.html", "temp2.xml");
dataBrowser.Navigate(Application.StartupPath + #"\temp2.html");
dataBrowser.Update();
waypoints = dir.coordsLat.Length;
counter = dir.coordsLat.Length;
coords = new double[dir.coordsLat.Length, 2];
for (int i = 0; i < counter; i++)
{
coords[i, 0] = (Convert.ToDouble(dir.coordsLat[i]));
coords[i, 1] = (Convert.ToDouble(dir.coordsLon[i]));
}
//serialPort1.Close();
//System.Threading.Thread.Sleep(1000);
if (serialPort1.IsOpen && !doubleClick)
{
serialPort1.Close();
System.Threading.Thread.Sleep(2000);
try
{
serialPort1.Open();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Cannot open serial port");
}
System.Threading.Thread.Sleep(2000);
}
else
{
if (!serialPort1.IsOpen)
{
try
{
serialPort1.Open();
doubleClick = true;
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Cannot open serial port");
}
System.Threading.Thread.Sleep(2000);
serialPort1.Write("^");
System.Threading.Thread.Sleep(1000);
Console.WriteLine('^');
//button3.Enabled = true;
}
}
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//System.Threading.Thread.Sleep(1000);
readData = serialPort1.ReadLine();
Console.WriteLine(readData);
// If microcontroller sends "&", it is ready to receive next piece of data
if (readData == "&")
{
sendRequest = true;
}
else
{
sendRequest = false;
}
// Write next piece of data to microcontroller if it is ready
if (sendRequest)
{
this.BeginInvoke( new EventHandler (write_serialPort1));
}
}
In during the debugging of code 1, the event handler (serialPort1_DataReceived) never gets called. In this process, somehow button3_click gets called twice as the console outputs '^' twice. Afterwards, the client stalls since there is nothing beind received. Keep in mind that the Arduino will respond with an ampersand ('&') once it has received the circumflex ('^'). The Arduino code has been tested on the Arduino IDE and appears to be working fine. I believe the problem with button3_click being called twice comes from the button3_down and button3_up.
However, I was able to bypass this issue with Code 2. But also hit another brick wall.
Code 2 :
private void button3_Click(object sender, EventArgs e)
{
// Disables button while processing
button3.Enabled = false;
GetDir dir = new App.GetDir();
dir.getCoords(Origin.Text, Destination.Text, Application.StartupPath + #"\temp2.html", "temp2.xml");
dataBrowser.Navigate(Application.StartupPath + #"\temp2.html");
dataBrowser.Update();
waypoints = dir.coordsLat.Length;
counter = dir.coordsLat.Length;
coords = new double[dir.coordsLat.Length, 2];
for (int i = 0; i < counter; i++)
{
coords[i, 0] = (Convert.ToDouble(dir.coordsLat[i]));
coords[i, 1] = (Convert.ToDouble(dir.coordsLon[i]));
}
serialPort1.Close();
try
{
serialPort1.Open();
}
catch (Exception exception)
{
MessageBox.Show(exception.Message, "Cannot open serial port");
}
if (serialPort1.IsOpen)
{
System.Threading.Thread.Sleep(2000);
using (serialPort1)
{
serialPort1.Write("^");
System.Threading.Thread.Sleep(1000);
Console.WriteLine("^");
serialPort1.Close();
System.Threading.Thread.Sleep(5000);
}
}
else
{
button3.Enabled = true;
}
}
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//SerialPort sp = (SerialPort)sender;
System.Threading.Thread.Sleep(10000);
/*if (!serialPort1.IsOpen)
{
serialPort1.Close();
System.Threading.Thread.Sleep(10000);
serialPort1.Open();
System.Threading.Thread.Sleep(10000);
}*/
//serialPort1.Open();
//using (sp)
using (serialPort1)
{
serialPort1.Open();
System.Threading.Thread.Sleep(5000);
readData = serialPort1.ReadExisting();
Console.WriteLine(readData);
// If microcontroller sends "&", it is ready to receive next piece of data
if (readData == "&")
{
sendRequest = true;
}
else
{
sendRequest = false;
}
// Write next piece of data to microcontroller if it is ready
if (sendRequest)
{
this.BeginInvoke(new EventHandler(write_serialPort1));
}
}
}
In Code 2, the event handler does get called and the button3_click only runs once. But when it tries to open the port, it returns the error 'Access to Port X denied'. Furthermore, I wish I didn't have to close and open the ports like this, but when the event handler is called (in an earlier code) it returned the error that the COM Port was not opened. In order to satisfy that error, I had to close it and reopen it during button3_click and event handling.
I've added a lot of delay in the code after I read about many problems dealing with the threading issues with serial communication. I had even tried a minute delay in hopes of a thread ending to solve the problem. However, no luck there.
I also specified my serial port in the MainForm designer instead of declaring it in the code (At first I did both and realized it was redundant). I'm not sure if this contributes to the problem, but I've seen examples of both being used.
Lastly, it could definitely deal with the Arduino auto resetting everytime a serial connection has been made (eg. opening and closing a port). In summary, it seems be sending data through serial, but unable to read the incoming data from serial.
Thank you for reading this and if someone could point me in the right direction, it would be very much appreciated.
Edit #1: Even after using BeginInvoke in Code 1, it still deadlocks because the event handler was never called.
Edit #2: Edits to Code 1 as per newbie's suggestions.
Edit #3: Added mainform initialization and updated Code 1 to current state.
Edit #4: Deleted (Commented out) the sleep at the event handler. I was sleeping during the event handler, thus I couldn't receive anything that the microcontroller would send to me. Code works fine as expected now.
Make sure you are using COM1, if you do not COM1 serial port,
change through Computer -> Device Manager -> Ports (COM & LPT) ->
Select the COM to be changed -> Port Settings -> Advanced -> ComPort Number -> select COM1.
Make sure that you have installed jumper / connect with a screwdriver
between pin2 and pin3 of COM1.
Add button1 and textBox1 to Form and run this program
using System;
using System.Windows.Forms;
using System.IO.Ports;
using System.Threading;
using System.Text;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
const int MAX_BUFFER = 100;
int i = 0;
byte[] DataReceived = new byte[MAX_BUFFER];
SerialPort serialPort = new SerialPort();
public Form1() {
InitializeComponent();
serialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
}
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) {
// wait data ready
Thread.Sleep(500);
// while data ready in buffer
while (serialPort.IsOpen && serialPort.BytesToRead > 0) {
// read data serial
DataReceived[i] = Convert.ToByte(serialPort.ReadByte());
// counter data
i++;
// reset conter if more then maxvalue
if (i >= MAX_BUFFER) {
i = 0;
}
}
if (i == 1 && DataReceived[0] == ASCIIEncoding.ASCII.GetBytes("^")[0]) {
this.textBox1.Invoke(new Action(() => {
this.textBox1.Text = ASCIIEncoding.ASCII.GetString(DataReceived, 0, 1);
}));
}
}
public void InitSerialPort() {
serialPort.PortName = "COM1";
serialPort.BaudRate = 9600;
serialPort.Parity = Parity.None;
serialPort.DataBits = 8;
serialPort.StopBits = StopBits.One;
serialPort.ReceivedBytesThreshold = 1;
}
private void Form1_Load(object sender, EventArgs e) {
// initialize serial port
InitSerialPort();
// assure port is closed before open it
if (serialPort != null && serialPort.IsOpen) {
serialPort.Close();
}
serialPort.Open();
}
private void button1_Click(object sender, EventArgs e) {
if (serialPort.IsOpen) {
serialPort.Write("^");
// wait data sent
Thread.Sleep(500);
}
}
}
}
In accordance to my 4th edit, deleted (Commented out) the sleep at the event handler. I was sleeping during the event handler, thus I couldn't receive anything that the microcontroller would send to me. Code works fine as expected now. Nothing was wrong with the serial ports on either components.

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

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.

Categories