Using c#, I would like to make a loop where it repeats the task only after the function before completes. Here's my code
TcpListener serv = new TcpListener(IPAddress.Any, 19148);
serv.Start();
TcpClient clie = serv.AcceptTcpClient();
NetworkStream stre = clie.GetStream();
byte[] buffer = new byte[2048];
Form1 f1 = new Form1();
f1.Show();
f1.TopMost = true;
///the code to repeat starts here
stre.Write(Encoding.UTF8.GetBytes("Enter Message: "), 0, Encoding.UTF8.GetByteCount("Enter Message: "));
stre.Read(buffer, 0, buffer.Length);
f1.label1.Text = Encoding.UTF8.GetString(buffer);
///ends here
I have read up on loops but every time I use one it crashes my program.
I have tried most things, but the most promising one so far has been this but it only shows the form on the last input.
int i = 0;
while(i < 3)
{
stre.Write(Encoding.UTF8.GetBytes("Enter Message: "), 0, Encoding.UTF8.GetByteCount("Enter Message: "));
stre.Read(buffer, 0, buffer.Length);
f1.label1.Text = Encoding.UTF8.GetString(buffer);
i++;
}
Any help would be appreciated as I have no leads to even point me in the right direction.
You really need to move the read to it's own thread (or use Async methods). You called .Show on the form, but the actual show isn't instantaneous, and it needs the thread you are using for your input to be able to draw itself. If you absolutely can't move your read loop to another thread (Async, BackgroundWorker, Task, etc), you could change your code to the following:
TcpListener serv = new TcpListener(IPAddress.Any, 19148);
serv.Start();
TcpClient clie = serv.AcceptTcpClient();
NetworkStream stre = clie.GetStream();
byte[] buffer = new byte[2048];
Form1 f1 = new Form1();
f1.Show();
f1.Refresh(); // Do it RIGHT NOW!
f1.TopMost = true;
int i = 0;
while(i < 3)
{
stre.Write(Encoding.UTF8.GetBytes("Enter Message: "), 0, Encoding.UTF8.GetByteCount("Enter Message: "));
stre.Read(buffer, 0, buffer.Length);
f1.label1.Text = Encoding.UTF8.GetString(buffer);
f1.label1.Refresh(); // Do it right now!
i++;
}
You will find that your form will display, but it is absolutely frozen. You can't resize it, it won't repaint itself until your loop finishes. Not a very good experience.
Related
I have created a TCP listener to receive data from a port. And I created a NetworkStream to read the coming data.
NetworkStream stream = new NetworkStream(TCPSocket);
Byte[] bytes = new Byte[128];
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
string msg = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("received: {0}", msg);
}
What I want to do is, if there is no data coming for 10 minutes, I want to close the stream. How can I do this? I have tried to use timer with creating a thread to call stream.close() after sometime, but nothing worked before it receive any data. Thanks in advance!
Try using:
stream.ReadTimeOut = 600000;
it is in milliseconds.
I have made a file receiving server in c# using socket programming. I have made a GUI . There is a button named 'connect' which will start the server on clicking it and there is a text box which will show a message when the server starts. But when I click on the button, the GUI freezes.
Here is my sample code:
using System;
using System.Drawing;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections.Generic;
class sampleserver : Form
{
private TextBox newText;
public TcpClient tcpClient;
public TcpListener tcpListener;
public sampleserver()
{
Text = " TCP Server";
Size = new Size(400, 380);
newText = new TextBox();
newText.Parent = this;
newText.Size = new Size(200, 2 * Font.Height);
newText.Location = new Point(10, 55);
Button connect = new Button();
connect.Parent = this;
connect.Text = "Connect";
connect.Location = new Point(295, 20);
connect.Size = new Size(6 * Font.Height, 2 * Font.Height);
connect.Click += new EventHandler(ButtonConnectOnClick);
}
void ButtonConnectOnClick(object obj, EventArgs ea)
{
tcpListener = new TcpListener(IPAddress.Any, 1234);
tcpListener.Start();
newText.Text = "Server started"; //**This line is not working**
//Infinite loop to connect to new clients
while (true)
{
// Accept a TcpClient
TcpClient tcpClient = tcpListener.AcceptTcpClient();
string address = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
byte[] data = new byte[1024];
NetworkStream ns = tcpClient.GetStream();
int recv = ns.Read(data, 0, data.Length);
StreamReader reader = new StreamReader(tcpClient.GetStream());
// The first message from the client is the file size
string cmdFileSize = reader.ReadLine();
int length = Convert.ToInt32(cmdFileSize);
byte[] buffer = new byte[length];
int received = 0;
int read = 0;
int size = 1024;
int remaining = 0;
// Read bytes from the client using the length sent from the client
while (received < length)
{
remaining = length - received;
if (remaining < size)
{
size = remaining;
}
read = tcpClient.GetStream().Read(buffer, received, size);
received += read;
}
}
}
public static void Main()
{
Application.Run(new sampleserver());
}
}
which change will I need to make to run this properly?
I would suggest you to use Asynchronous sockets but you can also make only that button click method Asynchronous , simply like this.
async void ButtonConnectOnClick(object obj, EventArgs ea)
{
tcpListener = new TcpListener(IPAddress.Any, 1234);
tcpListener.Start();
newText.Text = "Server started"; //**This line is not working**
await Task.Run(() =>
{
//Infinite loop to connect to new clients
while (true)
{
// Accept a TcpClient
TcpClient tcpClient = tcpListener.AcceptTcpClient();
string address = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
byte[] data = new byte[1024];
NetworkStream ns = tcpClient.GetStream();
int recv = ns.Read(data, 0, data.Length);
StreamReader reader = new StreamReader(tcpClient.GetStream());
// The first message from the client is the file size
string cmdFileSize = reader.ReadLine();
int length = Convert.ToInt32(cmdFileSize);
byte[] buffer = new byte[length];
int received = 0;
int read = 0;
int size = 1024;
int remaining = 0;
// Read bytes from the client using the length sent from the client
while (received < length)
{
remaining = length - received;
if (remaining < size)
{
size = remaining;
}
read = tcpClient.GetStream().Read(buffer, received, size);
received += read;
}
}
});
}
This would make the entire method asynchronous , and now you can read from the socket without freezing your main UI.
Goodluck.
UI events usually are meant to run and then return. Your program is launching code that should be started in a thread -- by the button code -- and then properly stopped when the application exits.
As Ron Beyer stated, you have a while(true), but I was more interested in whether the read times out or not and how you return to the main UI thread after the button is pushed. It looks like you never return to the main UI thread. As my comment stated, I'd test the network code, including the while loop in a console application, and then add on the complexities of a UI.
By the way, as other comments have pointed out, you cannot allow for a second click of your launch button, when you set up this code so the network setup (launch) succeeds. You'll have to disable (grey-out) the button, so it cannot be double-clicked, and only enabled if the network start (launch) failed. A second button, not greyed-out would allow you to shut everything down.
Threads and UIs are not the simplicity some would have you believe. They take quite a bit of work.
I am having a problem receiving data (a string of text) from an Arduino via a C# Winform app. The sketch on the Arduino basically reply with whatever I send. I am able to send data. What is strange is that if I telnet the device and type any text it responds correctly so it appears the problem is my C# code, however, I can't seem to figure out where I am incorrect.
Here is what I have
public partial class Form1 : Form
{
System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient();
NetworkStream serverStream = default(NetworkStream);
string readData = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(textBox2.Text);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
}
private void button2_Click(object sender, EventArgs e)
{
clientSocket.Connect("192.168.1.177", 5223);
readData = "Conected Arduino ...";
msg();
serverStream = clientSocket.GetStream();
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(textBox2.Text);
serverStream.Write(outStream, 0, outStream.Length);
serverStream.Flush();
Thread ctThread = new Thread(getData);
ctThread.Start();
}
private void getData()
{
while (true)
{
while (true)
{
serverStream = clientSocket.GetStream();
int buffSize = clientSocket.ReceiveBufferSize;
byte[] inStream = new byte[10025];
serverStream.Read(inStream, 0, buffSize);
string returndata = System.Text.Encoding.ASCII.GetString(inStream);
readData = "" + returndata;
msg();
}
}
}
private void msg()
{
this.BeginInvoke(new Action(() =>
{
textBox1.Text = String.Format("{0}{1} >> {2}", textBox1.Text, Environment.NewLine, readData);
}
));
}
}
Here is part of the Arduino sketch
void loop() {
// wait for a new client:
EthernetClient client = server.available();
// when the client sends the first byte, say hello:
if (client) {
if (!alreadyConnected) {
// clead out the input buffer:
client.flush();
Serial.println("We have a new client");
client.println("Hello, client!");
alreadyConnected = true;
}
if (client.available() > 0) {
// read the bytes incoming from the client:
char thisChar = client.read();
// echo the bytes back to the client:
//server.write(thisChar);
// echo the bytes to the server as well:
//Serial.write(thisChar);
if (inputPos < maxLength-1)
{
if (thisChar == '\n')
{
inputString[inputPos] = 0;
server.write(inputString);
Serial.write(inputString);
inputPos = 0;
} else {
// add it to the inputString:
inputString[inputPos] = thisChar;
inputPos++;
}
} else {
inputPos = 0;
}
}
}
}
Your code has a number of things wrong with it, including what has to be the most common novice error I've seen in any context: you fail to take into account the number of bytes actually read. Plus you have another common variation on the theme, which is that you process the entire receive buffer array as if the whole thing had valid data in it.
Without a way to test, it's hard to know for sure. But at the very least, you should change your receive method to look like this:
private void getData()
{
serverStream = clientSocket.GetStream();
while (true)
{
byte[] inStream = new byte[10025];
int bytesRead = serverStream.Read(inStream, 0, inStream.Length);
readData = System.Text.Encoding.ASCII.GetString(inStream, 0, bytesRead);
msg();
}
}
DON'T pointlessly nest a while (true) loop inside another while (true) loop
DON'T create a new NetworkStream every time you want to read
DON'T concern yourself with the Socket.ReceiveBufferSize property value
DO capture and use the return value from the read operation
DON'T concatenate the empty string with other strings (even in an iterated scenario, one should be using StringBuilder instead, and here you're not even iterating the concatenation!)
Of course, not all of those flaws are fatal. The biggest issues are the new NetworkStream on each read and the mismanagement of the receive buffer and result value. But really, you should strive for all of the code to be good.
Note that the above merely improves the code. Even the above still has a variation on "the most common novice error I've seen in any context": while it does use the return value from the read operation, it does not do everything with it that it should. In particular:
You are not actually guaranteed that you will receive all of the bytes that were sent to you in one read operation. This means your application protocol really should have some way for you to identify within the stream of bytes you're reading where one message ends and the next one starts.
When the connection is gracefully closed, the read operation will return 0 as the byte count, at which point your own code is supposed to respond by finishing up whatever writes to the socket you need to (if any) and then gracefully closing your own socket by calling Socket.Shutdown(SocketShutdown.Both) and finally Socket.Close().
But the above should at least help you make forward progress in your project.
One other thing you really should change IMHO which I didn't bother in the above, is that you should not use an instance field (i.e. readData) to pass data when simply passing it as a method parameter would suffice. You should avoid side-effects in your code as much as possible. It will make the code much easier to comprehend and thus to write correctly, among other things.
I have some pretty simple code that reads lines from a network stream that it connects to. In the code example only one line is every read and it doesn't carry on getting more from the server.
What is wrong?
byte[] readBuffer = new byte[1024];
byte[] tempBuff = new byte[1024];
int tempBuffSize = 0;
private void btnConnect_Click(object sender, EventArgs e)
{
TcpClient tcpClient = new TcpClient("192.168.1.151", 5505);
NetworkStream stream = tcpClient.GetStream();
stream.BeginRead(readBuffer, 0, 1024, readHandler, tcpClient);
}
void readHandler(IAsyncResult result)
{
TcpClient tcpClient = (TcpClient)result.AsyncState;
int dataLen = tcpClient.GetStream().EndRead(result);
int currStart = 0;
int currEnd = -1;
for (int i = 0; i < dataLen; i++)
{
if (readBuffer[i] == '\r' && i < (readBuffer.Length - 1) &&
readBuffer[i + 1] == '\n')
{
// Set the end of the data
currEnd = i - 1;
// If we have left overs from previous runs:
if (tempBuffSize != 0)
{
byte[] joinedData = new byte[tempBuffSize + (currEnd - currStart + 1)];
Array.Copy(tempBuff, 0, joinedData, 0, tempBuffSize);
Array.Copy(readBuffer, currStart, joinedData, tempBuffSize, (currEnd - currStart + 1));
System.Text.Encoding enc = System.Text.Encoding.ASCII;
string myString = enc.GetString(joinedData);
System.Diagnostics.Debug.Write(myString);
tempBuffSize = 0;
}
else
{
System.Text.Encoding enc = System.Text.Encoding.ASCII;
string myString = enc.GetString(readBuffer);
System.Diagnostics.Debug.Write(myString);
// HandleData(readBuffer, currStart, currEnd);
}
// Set the new start - after our delimiter
currStart = i + 2;
}
}
// See if we still have any leftovers
if (currStart < dataLen)
{
Array.Copy(readBuffer, currStart, tempBuff, 0, dataLen - currStart);
tempBuffSize = dataLen - currStart;
}
}
Why do you expect it to read the whole information in the first place? I am not an expert but it seems to me that neither the synchronous nor the asynchronous methods guarantee reading all the data (whatever that means because as long as a socket is open more data can arrive). After the code in your EndRead method you should call Read or BeginRead again if you expect more data. You should know if more data is expected based on the protocol you've established with the client.
I have faced similar issues when i developed tcp apps for an embedded device. In my case the problem was the device was giving out data in a delayed time and hence before the rest of the data can come in the control moves to the next line in the program fetching only the initial data from the server. I got around this by introducing a delay.
Just after the line where you read data from the server introduce a delay and for that reason it would be better to run this on a separate thread
thread.sleep(3000)
This should be your problem most probably.
maybe your stream object got disposed when it got out of scope, before the readHandler could be called again. try promoting tcpClient and stream to class scope instead of method scope, or move the reading to a separate thread that exits when the operation has finished.
I try to use stream.DataAvailable to judge if it is finished,but sometimes the value is false but after a little while it is true again,i have to set a counter and judge the end by the symbol '>' like this
int connectCounter = 0;
while (connectCounter < 1200)
{
if (stream.DataAvailable)
{
while (stream.DataAvailable)
{
byte[] buffer = new byte[bufferSize];
int flag = stream.Read(buffer, 0, buffer.Length);
string strReadXML_t = System.Text.Encoding.Default.GetString(buffer);
strReadXML = strReadXML + strReadXML_t.Replace("\0", string.Empty);
}
if (strReadXML.Substring(strReadXML.Length - 1, 1).Equals(">"))
{
break;
}
}
Thread.Sleep(100);
connectCounter++;
}
is there any good methord to deal with it?Thank you!
You have a couple options. You can use a synchronous, blocking Read, or you can use an asynchronous IO pattern.
If you simply call stream.Read(), the call will block, and wait forever (until the TCP timeout), until data is available. It seems you don't want to do that. You want to wait, at most, 120 seconds (1200ms * 100), for the data to be completely read.
Something like this:
private class AsyncState
{
public NetworkStream ns;
public ManualResetEvent e;
public byte[] b;
public String strReadXML;
}
public void Run()
{
TcpClient client ;//= ...
NetworkStream networkStream = client.GetStream();
byte[] buffer = new byte[1024];
var completedEvent = new ManualResetEvent(false);
networkStream.BeginRead(buffer, 0, buffer.Length,
AsyncRead,
new AsyncState
{
b = buffer,
ns = networkStream,
e = completedEvent,
strReadXML = ""
});
// do other stuff here. ...
// finally, wait 120s for the reading to complete
bool success = completedEvent.WaitOne(1200*100, false);
if (!success)
{
client.Close();
}
}
private void AsyncRead(IAsyncResult ar)
{
AsyncState state = ar as AsyncState;
int n = state.ns.EndRead(ar);
if (n == 0)
{
// no more bytes to read
// signal completion
state.e.Set();
return;
}
// state.buffer now contains the bytes read
string s = System.Text.Encoding.Default.GetString(state.b);
state.strReadXML = state.strReadXML + s.Replace("\0", string.Empty);
if (state.strReadXML.EndsWith(">"))
{
// got the "end". signal completion
state.e.Set();
return;
}
// read again
state.ns.BeginRead(state.b, 0, state.b.Length, AsyncRead, state);
}
Try asynchronous reading.
When your callback is called, you can read the existing data buffer and then call
BeginRead again. So that when somre more data is received, you callback will be called again.
Something like:
void DataReceived(IAsyncResult result) ///I am not sure about the parameters.
{
///read data from buffer
networkstream.BeginRead(
buffer, 0, buffer.Length,
new AsyncCallback(DataReceived),
null);
}
I think this is a pretty decent approach.
Do you have control over the sending application? If you do you can change the sending application to wrap the NetworkStream in a BinaryWriter and use .Write( string ) which will send the length of the string, and then the string itself. On the receiving application (as above) you can wrap the NetworkStream in a BinaryReader and call .ReadString() which will read the length from the stream, then read the correct length string in for you.
If you don't have control over the sending application then you can check the return from the stream.Read() call as it returns 0 at the end of the stream - though this will require the sending application to have closed the socket.
Also, stream.Read() is not guaranteed to return the number of bytes you requested, it could return less. Your flag variable should really be bytesread, and you should then pass this bytesread variable to the .GetString method.