I want to stop my thread on button click event and As I am new to threads I don't know how can I do this in C#. My application is of TCP Client and I am reading TCP server continuously using this thread
public void ClientReceive()
{
try
{
stream = client.GetStream(); //Gets The Stream of The Connection
new Thread(() => // Thread (like Timer)
//Thread mythread = new Thread(ClientReceive);
{
//MessageBox.Show(stream.Read(datalength, 0, 256).ToString());
//(i = stream.Read(datalength, 0, 256)) != 0
while (i != 1)//Keeps Trying to Receive the Size of the Message or Data
{
// how to make a byte E.X byte[] examlpe = new byte[the size of the byte here] , i used BitConverter.ToInt32(datalength,0) cuz i received the length of the data in byte called datalength :D
// byte[] data = BitConverter.GetBytes(1000); // Creates a Byte for the data to be Received On
byte[] data = new byte[1000];
stream.Read(data, 0, data.Length); //Receives The Real Data not the Size
this.Invoke((MethodInvoker)delegate // To Write the Received data
{
//txtLog.Text += System.Environment.NewLine + "Server : " + Encoding.Default.GetString(data); // Encoding.Default.GetString(data); Converts Bytes Received to String
DateTime now = DateTime.Now;
//MessageBox.Show(Encoding.Default.GetString(data));
if (Encoding.Default.GetString(data) != "")
{
txtLog.Text += System.Environment.NewLine + now.ToString() + " Received : \r\n" + Encoding.Default.GetString(data) + "\r\n";
}
for (int j = 0; j < txtLog.Lines.Length; j++)
{
if (txtLog.Lines[j].Contains("Received"))
{
this.CheckKeyword(txtLog.Lines[j + 1], Color.Red, 0);
}
if (txtLog.Lines[j].Contains("Sent"))
{
this.CheckKeyword(txtLog.Lines[j + 1], Color.Blue, 0);
}
}
});
}
// mythread.Start();
}).Start(); // Start the Thread
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
I recommend you to use Task instead of Thread. Because Aborting a thread is not recommnded and it may affect your data as well.
Eric Lippert explained it very well here.
Here is the code for you:
private CancellationTokenSource tokenSource; //global field
public void ClientReceive()
{
try
{
//initiate CancellationTokenSource
tokenSource = new CancellationTokenSource();
stream = client.GetStream(); //Gets The Stream of The Connection
//start parallel task
Task.Factory.StartNew(() =>
{
//MessageBox.Show(stream.Read(datalength, 0, 256).ToString());
//(i = stream.Read(datalength, 0, 256)) != 0
while (i != 1)//Keeps Trying to Receive the Size of the Message or Data
{
// how to make a byte E.X byte[] examlpe = new byte[the size of the byte here] , i used BitConverter.ToInt32(datalength,0) cuz i received the length of the data in byte called datalength :D
// byte[] data = BitConverter.GetBytes(1000); // Creates a Byte for the data to be Received On
byte[] data = new byte[1000];
stream.Read(data, 0, data.Length); //Receives The Real Data not the Size
this.Invoke((MethodInvoker)delegate // To Write the Received data
{
//txtLog.Text += System.Environment.NewLine + "Server : " + Encoding.Default.GetString(data); // Encoding.Default.GetString(data); Converts Bytes Received to String
DateTime now = DateTime.Now;
//MessageBox.Show(Encoding.Default.GetString(data));
if (Encoding.Default.GetString(data) != "")
{
txtLog.Text += System.Environment.NewLine + now.ToString() + " Received : \r\n" + Encoding.Default.GetString(data) + "\r\n";
}
for (int j = 0; j < txtLog.Lines.Length; j++)
{
if (txtLog.Lines[j].Contains("Received"))
{
this.CheckKeyword(txtLog.Lines[j + 1], Color.Red, 0);
}
if (txtLog.Lines[j].Contains("Sent"))
{
this.CheckKeyword(txtLog.Lines[j + 1], Color.Blue, 0);
}
}
});
}
}, tokenSource.Token);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
//call this method on cancel button
private void cancelTask()
{
if(tokenSource != null) //check if its even initialized or not
tokenSource.Cancel();
}
If you need more explanation about TPL refer to this article.
Try this:
Thread thread = new Thread(() =>
{
Console.WriteLine("Some actions inside thread");
});
thread.Start();
thread.Abort();
First you need to set your thread to some field and then you can control it as shown in code, Start(),Abort().
If you want Abort() thread from button click event you need to move thread field out of method, that way you can get access from your button click event.
Hope Helps!
Related
I have a namedpipeServerStream and I want to stop Reading its pipe when I meet the timeout.
these are my Read and Read callback function , and I call Read in my main program loop repeatedly,
Actually my question is how can I call my callback function manually(or any other way)when timeout happened for endread.
private void Read()
{
tmpBuff = new byte[600];
inRead = true;
ReadTimer.Enabled = true;
len = 0;
try
{
_namedpipeserver.BeginRead(tmpBuff, 0, 600, ReadCallback, null);
}
catch (Exception ex) //disconnected/disposed
{
return;
}
}
static void ReadCallback(IAsyncResult ar)
{
int readbyte;
try
{
readbyte = _namedpipeserver.EndRead(ar);
if (readbyte > 0)
{
len = readbyte;
int packetLen = tmpBuff[0] + (tmpBuff[1] * 256);
Console.WriteLine(" packet len: " + packetLen + " bytes ");
readbyte = 0;
array = null;
array = new byte[packetLen];
Array.Copy(tmpBuff, 2, array, 0, packetLen);
}
}
catch (IOException) //closed
{
return;
}
inRead = false;
}
Any help Appreciated.Thanks
I resolved this problem by disposing connection after a defined timeout and waiting for other side of the pipe to connect again.
Task.Run(() =>
{
tmpBuff = new byte[600];
readbyte = _namedpipeserver.Read(tmpBuff, 0, 600);
}).Wait(10000);
if (readbyte <= 0)
return null;
In case null returned try to reinitiate pipe.
I found TCPListener code from here.
In MainWindow class Im starting server.
Then opening websocket from html page
let socket = new WebSocket("ws://192.168.1.149:1112");
Right after this CPU loads to 25% even if nothing sent to server. Further data sending to server going normal. What to do to prevent CPU load? Please help.
class TcpServer
{
public string ip;
public int port;
private Thread bgThread;
public void StartListen()
{
bgThread = new Thread(new ThreadStart(Start))
{
IsBackground = true
};
bgThread.Start();
}
public void Start()
{
TcpListener server = new TcpListener(IPAddress.Parse(ip), port);
server.Start();
TcpClient client = server.AcceptTcpClient();
NetworkStream stream = client.GetStream();
while (true)
{
while (!stream.DataAvailable) ;
while (client.Available < 3) ; // match against "get"
byte[] bytes = new byte[client.Available];
stream.Read(bytes, 0, client.Available);
string strbytes = Encoding.UTF8.GetString(bytes);
if(strbytes.StartsWith("GET"))
{
Console.WriteLine("=====Handshaking from client=====\n{0}", strbytes);
string swk = Regex.Match(strbytes, "Sec-WebSocket-Key: (.*)").Groups[1].Value.Trim();
string swka = swk + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
byte[] swkaSha1 = System.Security.Cryptography.SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(swka));
string swkaSha1Base64 = Convert.ToBase64String(swkaSha1);
// HTTP/1.1 defines the sequence CR LF as the end-of-line marker
byte[] response = Encoding.UTF8.GetBytes(
"HTTP/1.1 101 Switching Protocols\r\n" +
"Connection: Upgrade\r\n" +
"Upgrade: websocket\r\n" +
"Sec-WebSocket-Accept: " + swkaSha1Base64 + "\r\n\r\n");
stream.Write(response, 0, response.Length);
}
else
{
bool mask = (bytes[1] & 0b10000000) != 0;
int msglen = bytes[1] - 128,
offset = 2;
if (msglen == 126)
{
msglen = BitConverter.ToUInt16(new byte[] { bytes[3], bytes[2] }, 0);
offset = 4;
}
else if (msglen == 127)
{
Console.WriteLine("TODO: msglen == 127, needs qword to store msglen");
}
if (msglen == 0)
Console.WriteLine("msglen == 0");
else if (mask)
{
try
{
byte[] decoded = new byte[msglen];
byte[] masks = new byte[4] { bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3] };
offset += 4;
for (int i = 0; i < msglen; ++i)
decoded[i] = (byte)(bytes[offset + i] ^ masks[i % 4]);
string text = Encoding.UTF8.GetString(decoded);
// other code
}
catch(Exception exc)
{
Console.WriteLine(exc.Message + "\n--------\n" + exc.StackTrace);
}
}
else
Console.WriteLine("mask bit not set");
}
}
}
}
private void startServer()
{
tcpserver = new TcpServer
{
ip = ipbox.Text,
port = 1112
};
tcpserver.StartListen();
}
startServer();
P.S: I have not to say anymore but SO says "It looks like your post is mostly code; please add some more details.". So: some words
I am trying to send a flatteded DBl array from labview to c# through tcp.
i am receiving the flattened string in c#.
i dont know how to convert them back to DBL array?
This is my code in C#:
{
private TcpClient socketConnection;
private Thread clientReceiveThread;
void Start()
{
ConnectToTcpServer();
}
void Update()
{
}
private void ConnectToTcpServer()
{
try
{
clientReceiveThread = new Thread(new ThreadStart(ListenForData));
clientReceiveThread.IsBackground = true;
clientReceiveThread.Start();
}
catch (Exception e)
{
Debug.Log("On client connect exception " + e);
}
}
private void ListenForData()
{
try
{
socketConnection = new TcpClient("localhost", 5333);
Byte[] bytes = new Byte[4000];
while (true)
{
using (NetworkStream stream = socketConnection.GetStream())
{
int length;
while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
{
Debug.Log(bytes.Length);
var incomingData = new byte[length];
Array.Copy(bytes, 0, incomingData, 0, length);
// Convert byte array to string message.
string serverMessage = Encoding.ASCII.GetString(incomingData);
Debug.Log("server message received as: " + serverMessage);
Debug.Log(serverMessage.Length);
}
}
}
}
catch (SocketException socketException)
{
Debug.Log("Socket exception: " + socketException);
}
}
}
This is my labview code:
This is my labview output: (Float array and flattened string)
This is the output in C#:
Since you wired FALSE to the "prepend array or string size", the only data in the buffer is the flattened doubles themselves. But you need to explicitly set "little endian" in order to talk to C#.
If you make that change in the G code, then this should work:
double[] dblArray = (double[])Array.CreateInstance(typeof(System.Double), length / 8);
// I'm not sure if you need the cast or not.
You have the constant "4000" in your code. I would change that to a declared constant and put a comment next to it that says, "Make sure this is a multiple of 8 (number of bytes in double data type)."
Below I attached a segment of code I have in my server. It is the main segment that controls all incoming client messages. Some messages are just strings where others are images. It works sometimes but other times the while loop (will label) will break before the whole image is done.
I am not sure if there is a better way to detect what is being sent over because at the moment I have it just looking for key words to see if it's an image.
Main issue isn't how to detect if incoming bytes are images because it seems to not be a problem search for words like PNG and such... the main concern is the permature breaking of the while loop indicated below
Also I noted that the while loop performs normally on my laptop and not my desktop for one reason or another. Might be a fuke but I am not sure if this statement is useful.
if (stream.DataAvailable)
{
Task DataInterpetTask = Task.Factory.StartNew(() =>
{
byte[] buffer = new byte[0];
byte[] tbuffer;
int rLength, prevLength;
byte[] buf = new byte[c.getClientSocket().ReceiveBufferSize];
//below is the while loop that breaks early
while (stream.DataAvailable)
{
rLength = stream.Read(buf, 0, buf.Length);
if (rLength < buf.Length)
{
byte[] temp = new byte[rLength];
Array.Copy(buf, temp, rLength);
buf = temp;
}
prevLength = buffer.Length;
tbuffer = buffer;
buffer = new byte[buffer.Length + rLength];
Array.Copy(tbuffer, buffer, tbuffer.Length);
buf.CopyTo(buffer, prevLength);
MainWindow.mainWindowDispacter.BeginInvoke(PrintDebugLog, new Object[] { "prevLength : " + prevLength + " new Length: " + buffer.Length });
}
// below searches for image related key words seems to work but if loop above
//break early I only get part of an image
String msg = Encoding.ASCII.GetString(buffer);
if (msg.Contains("PNG") || msg.Contains("RBG") || msg.Contains("HDR"))
{
RowContainer tempContainer;
if ((tempContainer = MainWindow.mainWindow.RowExists(c)) != null)
{
tempContainer.Image = buffer;
MainWindow.mainWindowDispacter.BeginInvoke(new Action(() =>
MainWindow.mainWindow.UpdateRowContainer(tempContainer, 0)));
}
else
{
MainWindow.mainWindowDispacter.BeginInvoke(new Action(() =>
MainWindow.mainWindow.CreateClientRowContainer(c, buffer)));
}
return;
}
if (msg.Length < 4)
return;
// The rest of the image is handle here like its some sort of string message...
String switchString = msg.Substring(0, 4);
if (msg.Length > 4)
msg = msg.Substring(4);
MainWindow.mainWindowDispacter.BeginInvoke(new Action(() =>
{
if (MainWindow.debugWindow != null)
MainWindow.debugWindow.LogTextBox.AppendText("Received message " + msg + " from client: " + c.getClientIp() + " as a " + switchString + " type" + Environment.NewLine);
}));
switch (switchString)
{
case "pong":
c.RespondedPong();
break;
case "stat":
RowContainer tContain = MainWindow.mainWindow.RowExists(c);
if (tContain == null)
break;
tContain.SetState(msg);
MainWindow.mainWindow.UpdateRowContainer(tContain, 1);
break;
}
});
}
}
Here is some updated code that works for those who need to understand it.
Server side:
if (stream.DataAvailable)
{
Task DataInterpetTask = Task.Factory.StartNew(() =>
{
int totalBuffer, totalRecieved = 0;
byte[] totalBufferByte = new byte[4];
byte[] buffer = new byte[0];
byte[] tbuffer;
int rLength, prevLength;
byte[] buf = new byte[c.getClientSocket().ReceiveBufferSize];
stream.Read(totalBufferByte, 0, 4);
totalBuffer = BitConverter.ToInt32(totalBufferByte, 0);
totalBuffer = totalBuffer - 3;
while (totalBuffer > totalRecieved)
{
rLength = stream.Read(buf, 0, buf.Length);
totalRecieved = rLength + totalRecieved;
if (rLength < buf.Length)
{
byte[] temp = new byte[rLength];
Array.Copy(buf, temp, rLength);
buf = temp;
}
prevLength = buffer.Length;
tbuffer = buffer;
buffer = new byte[buffer.Length + rLength];
Array.Copy(tbuffer, buffer, tbuffer.Length);
buf.CopyTo(buffer, prevLength);
}
String msg = Encoding.ASCII.GetString(buffer);
if (msg.Contains("PNG") || msg.Contains("RBG") || msg.Contains("HDR"))
{
RowContainer tempContainer;
if ((tempContainer = MainWindow.mainWindow.RowExists(c)) != null)
{
tempContainer.Image = buffer;
MainWindow.mainWindowDispacter.BeginInvoke(new Action(() =>
MainWindow.mainWindow.UpdateRowContainer(tempContainer, 0)));
}
else
{
MainWindow.mainWindowDispacter.BeginInvoke(new Action(() =>
MainWindow.mainWindow.CreateClientRowContainer(c, buffer)));
}
return;
}
String switchString = msg.Substring(0, 4);
if (msg.Length > 4)
msg = msg.Substring(4);
MainWindow.mainWindowDispacter.BeginInvoke(new Action(() =>
{
if (MainWindow.debugWindow != null)
MainWindow.debugWindow.LogTextBox.AppendText("Received message " + msg + " from client: " + c.getClientIp() + " as a " + switchString + " type" + Environment.NewLine);
}));
switch (switchString)
{
case "pong":
c.RespondedPong();
break;
case "stat":
RowContainer tContain = MainWindow.mainWindow.RowExists(c);
if (tContain == null)
break;
tContain.SetState(msg);
MainWindow.mainWindow.UpdateRowContainer(tContain, 1);
break;
}
});
}
}
Client side:
public void SendResponse(int command, Object[] args)
{
if (ClientSocket == null)
{
Console.WriteLine("Command: ClientSocket");
return;
}
var serverStream = this.ClientSocket.GetStream();
if (!serverStream.CanRead || !serverStream.CanWrite)
{
Console.WriteLine("Command: serverStream Error");
return;
}
byte[] toSend = null;
switch (command)
{
// 0 - genneral, 1 - handshake response
case 0:
toSend = Encoding.ASCII.GetBytes(args[0].ToString());
break;
case 1:
Rectangle bounds = Screen.GetBounds(Point.Empty);
using (Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height))
{
using (Graphics g = Graphics.FromImage(bitmap))
{
g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
}
toSend = ImageToByte(bitmap);
}
break;
}
if (toSend == null)
Console.WriteLine("what happened");
try
{
byte[] bufferedToSend = new byte[toSend.Length + 4];
byte[] lengthOfSend = BitConverter.GetBytes(toSend.Length);
Array.Copy(lengthOfSend, bufferedToSend, 4);
toSend.CopyTo(bufferedToSend, 4);
Console.WriteLine("Sending " + toSend.Length + " bytes" + " buffer len: "+bufferedToSend.Length);
serverStream.Write(bufferedToSend, 0, bufferedToSend.Length);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
I'm trying to handle my incoming buffer and ensure that I got all the 125 bytes of the data at each transmission. I've created a byte array. How can I know 125 bytes of data is being received. I tried displaying the number of bytes but it displayed different number and I'm unsure if it's the right coding to get the number of bytes received.
Here's my code:
void datareceived(object sender, SerialDataReceivedEventArgs e)
{
myDelegate d = new myDelegate(update);
listBox1.Invoke(d, new object[] { });
}
public void update()
{
Console.WriteLine("Number of bytes:" + serialPort.BytesToRead); // it shows 155
while (serialPort.BytesToRead > 0)
bBuffer.Add((byte)serialPort.ReadByte());
ProcessBuffer(bBuffer);
}
private void ProcessBuffer(List<byte> bBuffer)
{
// Create a byte array buffer to hold the incoming data
byte[] buffer = bBuffer.ToArray();
// Show the user the incoming data // Display mode
for (int i = 0; i < buffer.Length; i++)
{
listBox1.Items.Add("SP: " + (bBuffer[43].ToString()) + " " + " HR: " + (bBuffer[103].ToString()) + " Time: ");
}
}
At the moment you are reading until the local receive buffer (BytesToRead) is empty, however, a better approach is to keep a buffer and offset, and loop until you have what you need, even if that means waiting - i.e.
byte[] buffer = new byte[125]
int offset = 0, toRead = 125;
...
int read;
while(toRead > 0 && (read = serialPort.Read(buffer, offset, toRead)) > 0) {
offset += read;
toRead -= read;
}
if(toRead > 0) throw new EndOfStreamException();
// you now have all the data you requested