I am writing an application to send/receive some data to and from a server. I need to make a connection before sending some data and need to keep it open so that user can send data continuously. The user can close the connection at any time by clicking on disconnect button. I created 2 buttons, one to connect and one to disconnect.
Code behind Disconnect button is as below:-
private void button1_Click(object sender, EventArgs e)
{
if (tcpclnt.Connected)
{
tcpclnt.Client.Disconnect(false);
stm.Close();
}
else
{
MessageBox.Show("Not Connected");
}
}
code behind connect button is as below:-
public ASCIIEncoding asen = new ASCIIEncoding();
public TcpClient tcpclnt = new TcpClient();
public NetworkStream stm;
private void Connect_Click(object sender, EventArgs e)
{
if (!tcpclnt.Connected)
{
tcpclnt.Connect("XX.XX.XX.XX", 5500);
MessageBox.Show("Connected to server");
stm = tcpclnt.GetStream();
string sysname = "000B0000" + SystemName.Text.ToString();
byte[] sys1 = asen.GetBytes(sysname);
sys1[0] = 0; sys1[1] = 0;
sys1[2] = 0; sys1[3] = 0xB;
sys1[4] = 0; sys1[5] = 0;
sys1[6] = 0; sys1[7] = 0;
try
{
stm.Write(sys1, 0, sys1.Length);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
MessageBox.Show("Error in Sending data");
}
if (stm.DataAvailable)
{
try
{
byte[] bb = new byte[600];
int k = 8;
k = stm.Read(bb, 0, bb.Length);
string value = ASCIIEncoding.ASCII.GetString(bb, 8, k - 8);
MessageBox.Show(value.ToString());
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
MessageBox.Show("Error in Reading data");
}
}
}
else {
MessageBox.Show("Already Connected");
}
}
Now, when I click on Disconnect button and again click on connect button, it's throwing an exception on tcpclient.connect line. I don't understand why or how can I solve it.
Not an expert on this topic, but I think a possible solution would be to gracefully close the connection using tcpclnt.Close(). If you don't do this or let the garbage collector do it ungracefully, then you can't reconnect (I think). Close the stream, then close the tcpclnt rather than disconnect.
tcpclnt.GetStream().Close();
tcpclnt.Close();
Also, don't use tcpclnt.Connected to check if there's a connection. Just simply Close it.
EDIT
The above doesn't work. I don't know how to reuse the socket. This is how I got it to work...
private void DisconnectButton_Click(object sender, EventArgs e)
{
tcpclnt.Close();
tcpclnt = new TcpClient();
}
You mentioned that re-instantiating the object creates additional threads. This might be true as I'm unsure how to test for this. I opened up the windows resource monitor and watched the thread count for the app and it didn't show an additional thread opening each time.
Your .Disconnect() call needs to have true as the parameter to allow reuse. You currently are telling the socket to disallow reconnection. See here for the documentation.
Related
I am working on a program that receives data from a serial port and displays this on a GUI. I am very new to C# and this is a part of a project I am working on. I have tried to look for code for the past few weeks and watched every tutorial on this matter, all to fail. I am still very new to programming and OOP.
The issue I am having is that the received data is not being pasted in the display box. I have verified that the serial port works using Putty so that cannot be the issue.
Edit: Quick update, upon learning how to use the meter I am working with and closer inspection of the user manual, I discovered that I was able to connect to the meter using serialportname.open(). The issue was that I was not requesting data. For example, by writing "READ?" into the meter, a reading would be returned.
I see that you're not using the DataReceived event.
It could be an approach to what you're trying to achieve; it will trigger each time your serial port receives data, so you could use it to insert into the textbox1
private void serialPort1_DataReceived(object sender,SerialDataReceivedEventArgs e)
{
string Data= serialPort1.ReadLine();
displayToTxt(Data);
}
private void displayToTxt(string Data)
{
BeginInvoke(new EventHandler(delegate
{
textBox1.AppendText(Data);
}));
}
I used delegate to avoid thread errors.
first you need to add EventHandler
SerialPort1.DataReceived += new SerialDataReceivedEventHandler(ReceiveData);
then get data and update UI
public void ReceiveData(object sender, SerialDataReceivedEventArgs e)
{
System.Threading.Thread.Sleep(30);
SerialPort _SerialPort = (SerialPort)sender;
int _bytesToRead = _SerialPort.BytesToRead;
byte[] recvData = new byte[_bytesToRead];
_SerialPort.Read(recvData, 0, _bytesToRead);
this.BeginInvoke(new SetTextDeleg(UpdateUI), new object[] { recvData });
}
private void UpdateUI(byte[] data)
{
string str = BitConverter.ToString(data);
textBox1.Text += str;
}
I know this is old. But since it is still showing up in searches, I thought I would add my answer.
As mentioned in another answer, you need to assign a handler to the serial port.
public void OpenPorts()
{
foreach (string nm in SerialPort.GetPortNames())
{
SerialPort sp = new()
{
PortName = nm,
ReadBufferSize = 2048,
DiscardNull = true,
RtsEnable = true,
DtrEnable = true,
ReceivedBytesThreshold = 1
};
try
{
//This should throw an exception if the port is already open.
sp.Open();
sp.DataReceived += DataReceived;
//Make sure the buffer is empty
if (sp.BytesToRead != 0)
{
sp.DiscardInBuffer();
}
}
catch (Exception ex)
{
//Handle the exception here
}
}
public void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
while ((sender as SerialPort).BytesToRead > 0)
{
SerialBuffer += (sender as SerialPort).ReadExisting();
}
(sender as SerialPort).DiscardInBuffer();
}
catch (InvalidOperationException ex)
{
_ = MessageBox.Show("exception thrown at DataReceived.", "Crashed", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
Something really odd is happening to me.
I have ssh command which executes python script on my remote server.
When I execute it through PuTTY it works like it should and desired output is shown. But when executed through my C# app using ssh.net it always returns some old data that's long time gone from the server (which is freebsd 9.3).
Here's how I execute my command and catch output:
var task = new Task(() => {
var ret = ssh_instance.CreateCommand("cd /home/" + "python python_script.py -param");
ret.Execute();
FlexibleMessageBox.Show(ret.Result);
});
task.Start();
It seems literally unexplainable to me so I would be really thankful if someone could enlighten me what am I doing wrong.
Please remember.
Connection will closed after calling "CreateCommand()" method.
You need to read all of received data from your stream against your each command.
--> In my opinion, this is a reason why you've got old result from your connection.
So, I try to use Renci.SshNet.ShellStream class. in my code was,
private Renci.SshNet.SshClient _client = null;
private Renci.SshNet.ShellStream shellStream = null;
private void connect()
{
try
{
this.disConnect();
_client = new Renci.SshNet.SshClient(cboUri.Text, tbxSrvUsr.Text, tbxSrvPW.Text);
//_client.ErrorOccurred += new EventHandler<Renci.SshNet.Common.ExceptionEventArgs>(_client_ErrorOccurred);
//_client.HostKeyReceived += new EventHandler<Renci.SshNet.Common.HostKeyEventArgs>(_client_HostKeyReceived);
_client.Connect();
byte[] buffer = new byte[1000];
shellStream = _client.CreateShellStream("Jornathan", 80, 24, 800, 800, 1024);
shellStream.BeginRead(buffer, 0, buffer.Length, null, null);
shellStream.DataReceived += new EventHandler<Renci.SshNet.Common.ShellDataEventArgs>(shellStream_DataReceived);
tbxStatus.Text = "Connected";
this.btnConnect.Enabled = false;
this.cboServerList.Enabled = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
and add method to read all text from server.
Please remember, you should read all text until encounter received data size is "0". refer as below.
private void readOutput()
{
do
{
string strOutput = shellStream.ReadLine();
if (strOutput != null && strOutput.Length > 0)
{
System.Console.WriteLine(strOutput);
this.SetStatusText(strOutput);
}
else
{
break;
}
} while (true);
}
And then add event handler, that's it!.
private System.Threading.Thread Thread_OutputHandle = null;
private void shellStream_DataReceived(object sender, Renci.SshNet.Common.ShellDataEventArgs e)
{
if (Thread_OutputHandle == null)
{
Thread_OutputHandle = new System.Threading.Thread(new System.Threading.ThreadStart(readOutput));
Thread_OutputHandle.Start();
}
else if (Thread_OutputHandle.ThreadState == System.Threading.ThreadState.Stopped)
{
Thread_OutputHandle.Abort();
Thread_OutputHandle = new System.Threading.Thread(new System.Threading.ThreadStart(readOutput));
Thread_OutputHandle.Start();
}
}
Others:
I hope to remember where I've got help to make this code.
but I can't.
Please let me know when you find location of code that I've got help.
I'll add its location to here.
thanks in advance for anything.
Im making a server-client program, in which the server(application) creates a server and the client connects to it, i will also have a textbox and a button on the server application and whenever i write something on that textbox and press the button, it will send to the client application(there is only a textbox in this application, the only thing this application does is receive strings from the server application).
I think it works, kinda, but not the way i want it.
I can make the connection and also send and receive the information from the textboxs, but only if i run the server application first(to create the server). The problem is that if i dont run the server application first(to create the server), the client application won't connect, or even try to.
Example of "Error"(i guess you can call it an error):
If i run the client application first and then the server application, the client application just won't connect to the server that the server application created, i made a loop that basically verifies if the client is cnnected, if it is then it starts receiving the information, if not(else) waits for 3 seconds and tries to reconnect again. but when it tries to reconnect it doesnt work.
Any ideas?
CODE IN C#:
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) //connect to server
{
client = new TcpClient();
IPEndPoint IP_End = new IPEndPoint(IPAddress.Parse("192.168.254.34"), 123); // sincronizacao do IP com a porta
try
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IAsyncResult result = client.BeginConnect(IPAddress.Parse("192.168.254.34"), 123, null, null);
bool success = result.AsyncWaitHandle.WaitOne(3000, true);
while (success)
{
if (client.Connected)
{
STW = new StreamWriter(client.GetStream());
STR = new StreamReader(client.GetStream());
STW.AutoFlush = true;
backgroundWorker1.RunWorkerAsync(); // Começar a receber dados em background
backgroundWorker1.WorkerSupportsCancellation = true; // possibilidade de cancelar o fio
}
else
{
int milliseconds = 3000;
Thread.Sleep(milliseconds);
MessageBox.Show("swag do elias!");
client.Connect(IP_End);
}
}
}
catch (SocketException exception)
{
MessageBox.Show("O erro é:", exception.Source);
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) // Receber dados
{
while(client.Connected) //enquanto o cliente tiver conectado vai ler o que servidor diz em chat
{
try
{
receive = STR.ReadLine();
this.textBox2.Invoke(new MethodInvoker(delegate () { textBox2.Text=(receive + "\n\r"); }));
receive = "";
}
catch(Exception x)
{
MessageBox.Show(x.Message.ToString());
}
}
}
}
}
If the server isn't running yet, then success is always going to be false as a result of this line:
bool success = result.AsyncWaitHandle.WaitOne(3000, true);
Since success will always be false, the code inside of your while(success) block will never be executed.
Rearranging your code to something like this might be helpful:
client = new TcpClient();
bool success = false;
while (success == false)
{
try
{
IAsyncResult result = client.BeginConnect(IPAddress.Parse("192.168.254.34"), 123, null, null);
success = result.AsyncWaitHandle.WaitOne(3000, true);
}
catch (Exception ex)
{
success = false;
MessageBox.Show("error connecting: " + ex.Message + " : " + ex.StackTrace);
}
}
// NOW, by the time you reach this point, you KNOW that success == true and that you're connected, and you can proceed with the rest of your code
STW = new StreamWriter(client.GetStream());
STR = new StreamReader(client.GetStream());
STW.AutoFlush = true;
backgroundWorker1.RunWorkerAsync(); // Começar a receber dados em background
backgroundWorker1.WorkerSupportsCancellation = true; // possibilidade de cancelar o fio
i do have an embedded board (mini/tiny 210)
and i did try building an application which uses system.socket and system.socket.net in C# ( vs2005 - wince5 device application but i do have wince 6 on my device!! )
my purpose is to send and receive data bytes using Ethernet. for sending , well there is no problem but receive does need multitasking.
i should start a task so it can listen to the port if there is any data upcoming but once i add thread part to my code the whole program crashes (dose not do that in pc x64 core i5) but in embedded board it will crash.
if i eliminate multi tasking i might lose some data when networkstream.read is not online or when networkstream.read is online and i'm waiting for data,which ends in program will not respond up until the timeout. here is some of my codes . hope it helps.
this code does work :
private void button_connect_Click(object sender, EventArgs e)
{
try
{
//Thread TH = new Thread(new ThreadStart(con));
//TH.Start();
con();
}
catch
{
MessageBox.Show("THREAD ERROR");
}
}
public void con()
{
try
{
cli = null;
cli = new TcpClient();
cli.Connect(IPAddress.Parse(textBox_ip.Text),Convert.ToInt32(textBox_port.Text));
st = null;
st = cli.GetStream();
button_connect.Enabled = false;
button_Close.Enabled = false;
button_disconnect.Enabled = true;
statusBar1.Text = "Connected to server";
//Thread rec = new Thread(new ThreadStart(recf));
//rec.Start();
}
catch
{
MessageBox.Show("Connection faild","Error");
statusBar1.Text = "Faild to connect to server";
}
this code dose not work :
private void button_connect_Click(object sender, EventArgs e)
{
try
{
Thread TH = new Thread(new ThreadStart(con));
TH.Start();
//con();
}
catch
{
MessageBox.Show("THREAD ERROR");
}
}
public void con()
{
try
{
cli = null;
cli = new TcpClient();
cli.Connect(IPAddress.Parse(textBox_ip.Text),Convert.ToInt32(textBox_port.Text));
st = null;
st = cli.GetStream();
button_connect.Enabled = false;
button_Close.Enabled = false;
button_disconnect.Enabled = true;
statusBar1.Text = "Connected to server";
//Thread rec = new Thread(new ThreadStart(recf));
//rec.Start();
}
catch
{
MessageBox.Show("Connection faild","Error");
statusBar1.Text = "Faild to connect to server";
}
}
as you can see i'm getting this crash while just one of my task is in the code the second task has been commented
i appreciate your help in advance
The crash is probably caused by updating UI elements from a secondary thread.
The con method reads a textbox and updates several buttons as well as a status bar, and this should only happen on the main application thread.
To verify whether this is the issue, you could simply comment out the lines in the con method that access UI elements (copy the textbox value to a member string before starting the thread, or just hard-code the IP address) and re-run the application.
Then to actually fix the problem you'll have to look into Control.Invoke.
I have created 2 programs. Both use timers with interval set to 250 milliseconds.
The problem is that my first program doesn't lock then I run it, and the second locks with out giving me ability to click stop button. By saying locks I mean that program runs do it's job until I stop it from VS.
I don't understand why I can't stop my first program while the basic same way work for other program. Any ideas?
Program that locks:
private void btnScan_Click(object sender, EventArgs e)
{
tmrInterval.Interval = (int)nudInterval.Value;
tmrInterval.Start();
}
private void ScanPort(IPAddress address, int port)
{
using (TcpClient client = new TcpClient())
{
IAsyncResult result = client.BeginConnect(address, port, null, null);
if (result.AsyncWaitHandle.WaitOne((int)nudTimeout.Value, false)) txtDisplay.AppendText("Port: " + port + " is open." + Environment.NewLine);
else txtDisplay.AppendText("Port: " + port + " is closed." + Environment.NewLine);
}
}
private void btnStop_Click(object sender, EventArgs e)
{
tmrInterval.Stop();
}
private void tmrInterval_Tick(object sender, EventArgs e)
{
ScanPort(IPAddress.Parse(txtIP.Text), currentPort);
currentPort++;
if (currentPort == nudTo.Value) tmrInterval.Stop();
}
Program that doesn't lock:
void tmrPingInterval_Tick(object sender, EventArgs e)
{
if (txtTo.Text == string.Empty) Ping(IPAddress.Parse(ip2str(startIP)));
else
{
if (currentIP >= endIP) tmrPingInterval.Stop();
Ping(IPAddress.Parse(ip2str(currentIP)));
currentIP++;
}
}
private void btnPing_Click(object sender, EventArgs e)
{
if (txtFrom.Text != string.Empty)
{
txtFrom.Enabled = false;
txtTo.Enabled = false;
txtDisplay.Text = string.Empty;
tsslPingCount.Text = string.Empty;
count = 0;
open = 0;
closed = 0;
tmrPingInterval.Interval = int.Parse(nudInterval.Value.ToString());
try
{
startIP = str2ip(txtFrom.Text);
if (txtTo.Text != string.Empty) endIP = str2ip(txtTo.Text);
currentIP = startIP;
tmrPingInterval.Start();
}
catch
{
MessageBox.Show("Input must be in IP format: 100.100.100.100", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
txtFrom.Enabled = true;
txtTo.Enabled = true;
}
}
else MessageBox.Show("IP field cannot be empty!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void btnStop_Click(object sender, EventArgs e)
{
txtFrom.Enabled = true;
txtTo.Enabled = true;
tmrPingInterval.Stop();
}
private void Ping(IPAddress address)
{
Ping pingSender = new Ping();
PingOptions options = new PingOptions();
if (cbDontFragment.Checked) options.DontFragment = true;
else options.DontFragment = false;
string data = string.Empty;
int dataCounter = 0;
options.Ttl = (int)nudTTL.Value;
for (int i = 0; i < nudData.Value; i++)
{
dataCounter++;
if (dataCounter == 10) dataCounter = 0;
data += dataCounter.ToString();
}
byte[] buffer = Encoding.ASCII.GetBytes(data);
int timeout = 120;
try
{
PingReply reply = pingSender.Send(address, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
}
else
{
}
}
catch (Exception ex)
{
txtDisplay.SelectedText += Environment.NewLine + ex.Message;
}
}
I'm going to make a guess here since we don't have enough information. I am guessing that tmrInterval in a System.Windows.Forms.Timer. If that is the case, the what's happening is that when the timer ticks, it is handed as a windows message (the same way that mouse clicks, keystrokes, and everything else that make your application appear 'not frozen' are handled).
In the first application, you are doing something that takes substantial time- opening a TCP port, then waiting for a (presumably) large number of milliseconds until the TCP connects or doesnt, then almost immediately doing it again the next time that the timer ticks. You are literally never giving the application a chance to respond to mouse clicks and keystrokes because the UI thread is busy trying to connect to some random ports somewhere.
In the second application, you are doing something relatively quick- just sending a ping somewhere. what you will probably see in the second application is that your application will 'stutter'- become unresponsive for just a second or less while it pings whatever other machine you pointed it at. It doesn't get hung because the UI thread isn't being given that much work to do.
To fix both of these, you should look into implementing a BackgroundWorker. Timers (of any sort) are not generally considered a good way to spawn background tasks in .NET.
About the first sample:
I guess from the context that the timer is a Windows.Forms.Timer. In the elapsed event you are executing a WaitOne(), and so effectively block the Messagepump.
As a possible solution, replace the Timer with a Threading.Timer to decouple the I/O from the main Thread.