Cannot start a simple TCP/IP client - c#

I'm trying to open a TCP/IP listener but when I run the code below, it crashes. It doesn't give me an error because when it crashes, it freezes and stops responding.
TcpListener server = new TcpListener(IPAddress.Any, 619);
TcpClient client;
private void button3_Click(object sender, EventArgs e)
{
server.Start();
client = server.AcceptTcpClient();
if (client.Connected)
{
MessageBox.Show("connected");
}
}
I know for a fact this port is free so that's not it. it crashes on this line:
client = server.acceptTcpClient();

You're executing a blocking call on the UI thread which gives the appearance of a "Crashing" application.
You need to use another thread or do things asynchronously. Background worker might be a starting point.
private BackgroundWorker bgw = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
bgw.DoWork += Bgw_DoWork;
bgw.RunWorkerCompleted += Bgw_RunWorkerCompleted;
bgw.WorkerSupportsCancellation = true;
}
private void button3_Click(object sender, EventArgs e)
{
if (!bgw.IsBusy)
{
bgw.RunWorkerAsync();
((Button)sender).Content = "Cancel";
}
else
{
bgw.CancelAsync();
}
}
private void Bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
button.Content = "Start";
}
private void Bgw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
var server = new TcpListener(IPAddress.Any, 619);
server.Start();
while (true)
{
if (worker.CancellationPending)
{
e.Cancel = true;
server.Stop();
break;
}
else
{
if (server.Pending())
{
var client = listener.AcceptTcpClient();
// handle client here or do something like below to return the client to the RunWorkerCompleted method in
// e.result
e.Result = client;
break;
}
}
}
}
There are other options such as using server.AcceptTcpClientAsync() instead of polling the server.Pending() property. Also, polling in this way without using Thread.Sleep in between may be overkill, i.e., you're checking the property very frequently and wasting cycles.
Following all of that, you need to figure out a way to deal with the client in a way that makes sense for your application. One click per client accepted? Handle new connections forever as they arrive until you cancel the listener? Etc. Good luck
BackgroundWorker tutorial
AcceptTcpClientAsync MSDN

This is expected behaviour. Your program hasn't crashed - the call to AccpetTcpClient() blocks waiting for an incoming connection:
https://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.accepttcpclient(v=vs.110).aspx
You need to also open a TCP connection to port 619 from another thread, then your program will continue to run.

AcceptTcpClient is a blocking method
(https://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.accepttcpclient%28v=vs.110%29.aspx).
When you call AcceptTcpClient, it will wait until a connection is made. Because it waits on the main thread (where also the GUI is running on), it will look like the program is frozen. Try using AcceptTcpClientAsync or putting the accepting part in a different thread. That should solve your problem.
Desirius

Related

Design don't appear on Debug

I'm creating a C# Socket Server, it already works, but now, when I press "Start" the "design" of the application doesn't load, it's not visible.
The socket server is running correcty (I see it working in the output window), I don't see any kind of error. I start deleting parts of the code, and the design stops being visible after this line:
TcpClient client = server.AcceptTcpClient();
...
If I remove from this line to the end, it appear again.
What's going on? (sorry for my bad english)
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
start();
}
private void start() {
TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 1234);
server.Start();
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Client connected.");
}
I Think the problem is that the load is interrupted while the socket is working waiting for connections.
I'm trying to execute "start()" function on Form1_Shown but it does not work.
How can I be sure to start the socket server after the Form is full loaded?
server.AcceptTcpClient() is a blocking call and you are making it on the UI thread. You have a few options, here they are in the order I would do them.
Make the function you are calling it from async and use AcceptTcpClientAsync.
//Event handlers like `Load` are the only place you are allowed to do "async void"
private async void Form1_Load(object sender, EventArgs e)
{
await start();
}
private async Task start() {
TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 1234);
server.Start();
TcpClient client = await server.AcceptTcpClientAsync();
Console.WriteLine("Client connected.");
}
If you can't use async/await because of the version of .NET you are targeting use BeginAcceptTcpClient to have a callback accept the client instead.
private void Form1_Load(object sender, EventArgs e)
{
start();
}
private void start() {
TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 1234);
server.Start();
server.BeginAcceptTcpClient(AcceptClient, server);
}
private void AcceptClient(IAsyncResult result)
{
var server = (TcpListener)result.AsyncState;
TcpClient client = server.EndAcceptTcpClient(result);
Console.WriteLine("Client connected.");
}
Or one other option is put the code you currently have on a background thread via a Task.Run( or similar. However, I really would not recommend this approach, you tie up a thread just waiting for a new connection, the framework already provides better ways to do this without a thread by using async/await or the begin/end pair.
private void Form1_Load(object sender, EventArgs e)
{
Task.Run(() => start());
}
private void start() {
TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 1234);
server.Start();
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Client connected.");
}

C# Ping.Send causing GUI to freeze

first time using Stackoverflow so i'll try to do my best.
I was making a little app to ping some servers, the issue i'm having is that the GUI of the program locks up while it waits for a response.
This is what I have so far, Button_Click is the "Ping IP" button, ping_box is a textbox that will contain the response time, ip_address is a IP address in the form of a string.
private void Button_Click(object sender, RoutedEventArgs e)
{
Stopwatch s = new Stopwatch();
s.Start();
while (s.Elapsed < TimeSpan.FromSeconds(2))
{
using (Ping p = new Ping())
{
ping_box.Text = (p.Send(ip_address, 1000).RoundtripTime.ToString() + "ms\n");
if (ping_box.Text == "0ms\n")
{
ping_box.Text = "Server is offline or exceeds 1000ms.";
}
}
}
s.Stop();
}
So in its current state it pings the IP address repeatedly for two seconds and puts the response time into a textbox, during this time the GUI locks up though.
I need to recorrect this as I want the textbox with the response time to update with each ping (if the response time is 500 ms then the textbox should update four times).
I've tried to use Ping.SendAsync but could not get it to work, any pointers or help would be much appreciated :)
I think this should help...
You can modify it further as per your needs
private void button1_Click(object sender, EventArgs e)
{
AutoResetEvent waiter = new AutoResetEvent(false);
IPAddress ip = IPAddress.Parse("192.168.1.2");
var pingSender = new Ping();
pingSender.PingCompleted += PingCompletedCallback;
pingSender.SendAsync(ip, 1000, waiter);
}
private void PingCompletedCallback(object sender, PingCompletedEventArgs e)
{
// If an error occurred, display the exception to the user.
if (e.Error != null)
{
MessageBox.Show(string.Format("Ping failed: {0}", e.Error.ToString()),
"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
// Let the main thread resume.
((AutoResetEvent)e.UserState).Set();
}
DisplayReply(e.Reply);
// Let the main thread resume.
((AutoResetEvent)e.UserState).Set();
}
public void DisplayReply(PingReply reply)
{
if (reply == null)
return;
ping_box.Text = string.Format("Ping status: {0}, RoundTrip time: {1}",
reply.Status,
reply.RoundtripTime.ToString());
}
Ping
Allows an application to determine whether a remote computer is
accessible over the network.
When you called Ping, your Main Thread (and that is your UI Thread) has been halt and wait for ping respond, that's why your application freeze.
solution:
You need to put Ping in another Thread

Polling a web service

I have a C# desktop Windows form application.
Every 3 seconds I am invoking a call to a web service to check for messages in a directory on my server.
I have a while (true) loop, which was started by a thread. Inside this loop the call to the web service is made. I know I should avoid infinite loops, but I do not know an easy way of notifying my client of a new message in a timely fashion.
Are there alternatives I could look at please?
Thanks!
You can probably use a BackgroundWorker for this - tutorial
You'd still need to use while(true) loop but you can communicate to the client by use the BackgroundWorker's ReportProgress Method:
// start the BackgroundWorker somewhere in your code:
DownloadDataWorker.RunWorkerAsync(); //DownloadDataWorker is the BackgroundWorker
then write the handlers for DoWork and ProgressChanged
private void DownloadRpdBgWorker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
while (true)
{
worker.ReportProgress(1);
if (!controller.DownloadServerData())
{
worker.ReportProgress(2);
}
else
{
//data download succesful
worker.ReportProgress(3);
}
System.Threading.Thread.Sleep(3000); //poll every 3 secs
}
}
private void DownloadRpdBgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
switch(e.ProgressPercentage){
case 1: SetStatus("Trying to fetch new data.."); break;
case 2: SetStatus("Error communicating with the server"); break;
case 3: SetStatus("Data downloaded!"); break;
}
}
EDIT: Sorry for misreading. If you want to do something every 3 seconds, Use timers:
public static bool Stop = false;
public static void CheckEvery3Sec()
{
System.Timers.Timer tm = new System.Timers.Timer(3000);
tm.Start();
tm.Elapsed += delegate
{
if (Stop)
{
tm.Stop();
return;
}
...
};
}

Tell a window to close from a thread in C#

I am working in WPF and I have a dialog window that start a listen socket, and is supposed to close as soon as someone connect. Here is my naive, non working snippet code:
void acceptCallback(IAsyncResult iar)
{
socket = listenSocket.EndAccept(iar);
DialogResult = true; // error here
Close();
}
private void ValidButton_Click(object sender, RoutedEventArgs e)
{
IPEndPoint iep = new IPEndPoint(IPAddress.Any, port);
listenSocket.Bind(iep);
listenSocket.Listen(1);
listenSocket.BeginAccept(acceptCallback, null);
}
I get an error telling me that DialogResult can't be accessed from this thread, I understand that my "acceptCallback" function is called from the thread running the accept asynchronously, but don't really know how to get the behavior I want.
How can I tell the main thread from this callback that it is supposed to close the dialog window in a proper way ?
You can usually access UI elements (as the dialog window object) only from the UI thread.
That is simply done by using the Dispatcher of the UI element:
void acceptCallback(IAsyncResult iar)
{
socket = listenSocket.EndAccept(iar);
Dispatcher.Invoke(() =>
{
DialogResult = true;
Close();
});
}
In case it is .NET 4.0 or below, you have to explicitly create an Action from the lambda expression:
Dispatcher.Invoke(new Action(() =>
{
DialogResult = true;
Close();
}));
or
Dispatcher.Invoke((Action)(() =>
{
DialogResult = true;
Close();
}));

c# Thread won't add Row to DataGridView CrossThreadError

I am learning c# and I would like to know why my code won't add a row to my DataGridView in the ReceivePacket area. It works in the SendPacket but not in the other.
The purpose is to simply send a UDP packet to a machine, thanks in advance.
Here is my code:
private void btnSend_Click(object sender, EventArgs e)
{
SendPacket();
}
private void btnReceiving_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(reciev));
thread.Start();
}
UdpClient client = new UdpClient();
public void SendPacket()
{
byte[] packet = Encoding.ASCII.GetBytes(DateTime.Now.ToString("HH:mm:ss:ff"));
client.Send(packet, packet.Length, tbIP.Text, 444);
dgvSend.Rows.Add(DateTime.Now.ToString("HH:mm:ss:ff"));
}
public void ReceivePacket(byte[] packet)
{// it goes wrong here, because it gives a crossthread error
dgvReceiv.Rows.Add(Encoding.ASCII.GetString(packet), DateTime.Now.ToString("HH:mm:ss:ff"));
}
public void reciev()
{
UdpClient client = new UdpClient(444);
while (true)
{
IPEndPoint server = new IPEndPoint(IPAddress.Any, 0);
byte[] packet = client.Receive(ref server);
ReceivePacket(packet);
}
}
I fixed it using this line of code instead of the normal (with the invoke :) ):
dgvReceiv.Invoke(new MethodInvoker(delegate { dgvReceiv.Rows.Add(Encoding.ASCII.GetString(packet), DateTime.Now.ToString("HH:mm:ss:ff")); }));
Here you go example of using delegates to invoke actions from other threads on controls created on main thread.
http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx
The problem is that you're attempting to create a GUI element (a form) on another thread than the main GUI thread. You can only create GUI elements on the GUI thread. Anything else doesn't work.
You should receive the data in your secondary thread, and then copy it over to your GUI thread, to put it inside a GUI element. I think there's a function Control.Invoke that is a delegate that will invoke a function on the thread the Control was created on, which you could use to call from your secondary thread to actually populate your form or whatever control.

Categories