WPF - GUI not updating when calling different class? (TCP application) - c#

I have a fairly weird question? I have seen on web how to pass control from main class to another class, and this is said to work, but it does not?
What I am trying to do is create a simple asynchronous TCP client-server connection, which would send messsage from client to server. Problem is when I want to update client's textblock, application exits (no error just closes). I only have one main thread so I don't think I need to have an Invoke.
Code from main class:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void connect_ClickEvent(object sender, RoutedEventArgs e)
{
try
{
_statusPanel.Text += "Sending request to server (IP address: " + _ipTextBox.Text + ", port number: " + _portTextBox.Text + ")\n";
_statusPanel.Text += "Connecting.....\n";
AsynchronousClient.setStatusPanel(_statusPanel);
AsynchronousClient.setPort(Convert.ToInt32(_portTextBox.Text));
AsynchronousClient.setIpAddress(_ipTextBox.Text);
AsynchronousClient.StartClient(_message.Text);
_statusPanel.Text += "... connection established!\n";
_statusPanel.Text += "Enter the string to be transmitted !\n";
}
catch (Exception ee)
{
_statusPanel.Text += ee.StackTrace + "\n";
}
}
}
Code from another class:
public class AsynchronousClient
{
// The port number for the remote device.
private static int port;
private static IPAddress ipAd;
public static TextBlock statusPanel;
public static void setStatusPanel(TextBlock status)
{
statusPanel = status; //That's my setter for statusPanel which I want to update
}
public static void StartClient(string message)
{
// Connect to a remote device.
try
{
IPAddress ipAddress = ipAd;
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
string sendingMessage = message + "<EOF>";
Send(client, sendingMessage);
sendDone.WaitOne();
Receive(client);
receiveDone.WaitOne();
client.Shutdown(SocketShutdown.Both);
client.Close();
}
catch (Exception e)
{
statusPanel.Text += e.ToString() + "\n";
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
client.EndConnect(ar);
//This next line is where my program closes without error
statusPanel.Text = "Socket connected to " + client.RemoteEndPoint.ToString() + "\n";
connectDone.Set();
}
catch (Exception e)
{
statusPanel.Text += e.ToString() + "\n";
}
}
**If I replace "statusPanel.text" with "Console.WriteLine" everything works just fine! Anybody knows what I am doing wrong? **

AsyncCallback will be called on separate thread and not on main thread so you can't update textBox value from other thread. You can only do that from main UI thread.
So, you have to delegate it on main thread like this:
statusPanel.Dispatcher.Invoke(new Action(() =>
statusPanel.Text = "Socket connected to " +
client.RemoteEndPoint.ToString() + "\n"));

You method ConnectCallback will not be executed on the WPF User Interface thread, but instead will be invoked by the socket class on a background thread of the thread pool. In this method, you set the Text of the StatusPanel.
Use StatusOanel.Dispatcher.Invoke to execute your method on the UI Thread. If you want to learn more about it, this article might be a thing: http://msdn.microsoft.com/en-us/magazine/gg598924.aspx

Related

C# UDP Socket.ReceiveFrom() breaks loop without exeption

I'm trying to make a game using sockets and UDP, i made a server class where when i call the start method i run a task with a loop to receive packets and process them, i used Socket.ReceiveFrom(packet, ref sender); inside a try catch block with everything inside a while loop, first i forgot to add Socket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 25000)); so i got a loop of bind exeptions which is normal but now that i added this line my program is freaking out see the code bellow
public class UDPServer
{
public UDPServer()
{
Socket = new Socket(AddressFamily.InterNetwork ,SocketType.Dgram,ProtocolType.Udp);
Socket.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 25000));
}
public void Start()
{
IsBound = true;
try
{
Task.Run(NetworkLoop);
}
catch (Exception e)
{
throw e;
}
}
private void NetworkLoop()
{
EndPoint sender = new IPEndPoint(IPAddress.Any, 0);
byte[] packet = new byte[1];
int dataSize = 0;
while (IsBound)
{
try
{
dataSize = Socket.ReceiveFrom(packet, ref sender);
Console.WriteLine(sender.ToString() + " with " + packet.Length + " of " + dataSize);
}
catch (Exception e)
{
Console.WriteLine("Reading exeption : " + e.Message);
}
}
}
}
I debugged this and it seems that now when going step by step to the line
dataSize = Socket.ReceiveFrom(packet, ref sender); it just both exit the try catch block without any exeption catched AND breaks the while loop...
Is this normal behaviour ??
Your UDPServer.Start() method is not blocking, because Task.Run will run asynchronously.
Task.Run(NetworkLoop); // This is non-blocking
Your UDP server will work by either:
Task.Run(NetworkLoop).Wait(); // This is blocking
or
new UDPServer().Start();
Console.WriteLine("Press <enter> key to stop UDP server...");
Console.ReadLine(); // This block until user hit <enter> key

Foreach freezing form

I know there are plenty of things about foreach freezing forms but I can't find a solution to my problem. I already have the server portion of this program working I am trying to make a client side that while connecting to the server this code will be preformed txtConn.AppendText("Attempting connection.");
This is the code that I have for the socket connection
private static Socket ConnectSocket(string server, int port, RichTextBox txtConn, BackgroundWorker backgroundWorker1)
{
Socket s = null;
IPHostEntry hostEntry = null;
// Get host related information.
hostEntry = Dns.GetHostEntry(server);
// Loop through the AddressList to obtain the supported AddressFamily. This is to avoid
// an exception that occurs when the host IP Address is not compatible with the address family
// (typical in the IPv6 case).
backgroundWorker1.RunWorkerAsync();
foreach (IPAddress address in hostEntry.AddressList)
{
IPEndPoint ipe = new IPEndPoint(address, port);
Socket tempSocket =
new Socket(address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine(ipe);
try
{
attempt++;
txtConn.Select(txtConn.TextLength, 0);
txtConn.SelectionColor = Color.Aqua;
if (attempt == 1)
{
txtConn.AppendText("Attempting connection.");
}
else if (attempt > 1)
{
txtConn.AppendText("\r" + "Attempting connection.");
}
txtConn.SelectionColor = txtConn.ForeColor;
tempSocket.Connect(ipe);
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
txtConn.Select(txtConn.TextLength, 0);
txtConn.SelectionColor = Color.Red;
txtConn.AppendText("\r\n" + "Connection could not be established.");
txtConn.SelectionColor = txtConn.ForeColor;
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
txtConn.Select(txtConn.TextLength, 0);
txtConn.SelectionColor = Color.Red;
txtConn.AppendText("\r\n" + "Connection could not be established.");
txtConn.SelectionColor = txtConn.ForeColor;
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
txtConn.Select(txtConn.TextLength, 0);
txtConn.SelectionColor = Color.Red;
txtConn.AppendText("\r\n" + "Connection could not be established.");
txtConn.SelectionColor = txtConn.ForeColor;
}
if (tempSocket.Connected)
{
Console.WriteLine("Connected");
s = tempSocket;
break;
}
else
{
continue;
}
}
return s;
}
My program looks like this
When I run the program and connect with say the wrong Port, it checks all the possible ips on my computer and waits till after the foreach statement to display errors or anything. How can I make it actively display this?This is when it runs
You need to run your code in a different thread so that the UI can still update while it is executing.
The easiest way to do this is by adding the connection loop to a new task in the ThreadPool.
ThreadPool.QueueUserWorkItem(i => {
// Connection loop goes here.
});
If you need other options you can also use a Task, BackgroundWorker, etc.
I just answered a similar question here, but to expand on it for your particular case, it looks like you aren't actually using backgroundWorker1. The foreach should be done in a method referenced by the backgroundWorker1.DoWork event. You'll also need to create a method for the backgroundWorker1.ProgressChanged event. You can use ReportProgress to pass a string and then append that message to your textbox:
From your foreach loop in the Worker_DoWork method, you will report progress instead of updating the RichTextBox directly:
worker.ReportProgress(0, "Connection could not be established.");
And then in the Worker_ProgressChanged method, you will use something like this to update the RichTextBox:
txtConn.AppendText(e.UserState.ToString());
Use should use Async methods from Socket class or run this stuff in another thread. You can use BackgroundWorker to do that as well.

Using TcpListener.AcceptSocket(); in a separate thread causes the thread to block?

I have tried to work around this as well as debug but I'm at a loose end here :( is there any alternative to using this to check for a client connection? This code works fine in a console application so i am guessing the thread is being blocked, although it may be something else i can't see?
public partial class Form1 : Form
{
Socket s;
Declatation of socket.
private void startButton_Click(object sender, EventArgs e)
{
checkTimer.Enabled = true;
if (bw.IsBusy != true)
{
bw.RunWorkerAsync();
}
}
Background thread to start on button press.
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
working();
}
Thread runs the "working" method.
private void working()
{
if (threadFirstRun == true)
{
threadFirstRun = false;
}
try
{
String tempAddr = tbAddr.Text;
IPAddress ipAd = IPAddress.Parse("147.197.204.172");
// use local m/c IP address, and
// use the same in the client
String tempPort = tbPort.Text;
/* Initializes the Listener */
TcpListener myList = new TcpListener(ipAd, 3000);
/* Start Listeneting at the specified port */
myList.Start();
tcConnection1 = "Console:\n" + "The server is running at port 3000...";
tcConnection2 = "\n" + "The local End point is :" + myList.LocalEndpoint;
tcConnection3 = "\n" + "Waiting for a connection.....";
while (true)
{
s = myList.AcceptSocket();
if (s != null)
{
if (connectionEstab == false)
{
tcEstab = "\n" + "Connection accepted from " + s.RemoteEndPoint;
connectionEstab = true;
}
byte[] b = new byte[100];
int k = s.Receive(b);
//Console.WriteLine("Recieved...");
for (int i = 0; i < k; i++)
{
//Console.Write(Convert.ToChar(b[i]));
tcValue = tcValue + Convert.ToString(b[i]);
valueArray[ii] = (float)Convert.ToDouble(b[i]);
}
tcValue = tcValue + "\n";
ii++;
}
else
{
Thread.Sleep(200);
}
}
ASCIIEncoding asen = new ASCIIEncoding();
s.Send(asen.GetBytes("The string was recieved by the server."));
rtbConsole.Text = rtbConsole.Text + "\n" + "Sent Acknowledgement";
/* clean up */
s.Close();
myList.Stop();
}
catch (Exception ex)
{
tcError = "\n\n" + "Error..... " + ex.StackTrace;
}
}
Working method starts the server and blocks upon calling myList.AcceptSocket();?
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if ((e.Cancelled == true))
{
rtbConsole.Text = rtbConsole.Text + "\n" + "Canceled!";
}
else if (!(e.Error == null))
{
rtbConsole.Text = rtbConsole.Text + "\n\n" + ("Error: " + e.Error.Message);
}
else
{
rtbConsole.Text = rtbConsole.Text + "\n" + "Done!";
}
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
rtbConsole.Text = rtbConsole.Text + "\n" + (e.ProgressPercentage.ToString() + "%");
}
private void stopButton_Click(object sender, EventArgs e)
{
checkTimer.Enabled = false;
if (bw.WorkerSupportsCancellation == true)
{
bw.CancelAsync();
}
}
Other methods for some completeness.
Sending data from my android device is received by a console app running 1 thread, however nothing seems to happen in this windows form application upon sending data to the same ip and port from the same program on the same device. The separate thread just stays blocked and the android app cannot complete communication to send the data.
It's supposed to block. It can never return null. (Why is everybody doing this? It's like nobody on the web uses Accept correctly.)
Your problem is that after accepting one connection you process that connection and do nothing to resume accepting. The standard pattern is:
while (true) {
var connectionSocket = listeningSocket.Accept();
ProcessAsynchronously(connectionSocket);
}
Make sure ProcessAsynchronously returns immediately. Start a new Task or use async/await.
As you never exit the while loop you never get to sending data. Move all processing logic into ProcessAsynchronously.
It is supposed to block. From MSDN:
AcceptSocket is a blocking method that returns a Socket that you can
use to send and receive data. If you want to avoid blocking, use the
Pending method to determine if connection requests are available in
the incoming connection queue.
You can turn your whole implementation to use the async version: AcceptSocketAsync. Note this wont block your method, it will yield control back to the caller until a new Socket has been connected.
private async void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
await WorkingAsync();
}
And inside WorkingAsync:
private Task WorkingAsync
{
// Do all other stuff,
Socket socket = await myList.AcceptSocketAsync();
// Do rest of stuff with the socket
}
I recommend you like at What is the async/await equivalent of a ThreadPool server? for a full implementation of an async tcp connection handler

Accepting Connections asynchronous with a Proxy Server

When I want to open a new Thread for every Incoming Request. Is this good way to do it? Will there be a new Thread with every accepted Request? The BeginReceive Method called in the end of this piece of code Works asynchronous aswell.
public void Listen(IPEndPoint EndPoint)
{
try
{
ListeningSocket.Bind(EndPoint);
ListeningSocket.Listen(BACKLOG);
BeginAccept();
}
catch (Exception e)
{
Console.WriteLine(e.Message + "\nfrom Source: " + e.Source + "\nand Stack Trace: " + e.StackTrace);
}
}
public void BeginAccept()
{
try
{
ListeningSocket.BeginAccept(new AsyncCallback(Accept_Callback), new ServerSocket());
}
catch (SocketException e)
{
Console.WriteLine("Listening Socket Error:" + e.ErrorCode);
}
catch (ObjectDisposedException e)
{
Console.WriteLine("The Listening Socket has been closed");
}
}
private void Accept_Callback(IAsyncResult asyncResult)
{
BeginAccept();
try
{
if (asyncResult.AsyncState != null)
{
ServerSocket serverSocket = asyncResult.AsyncState as ServerSocket;
if ((serverSocket.CommunicationSocket = ListeningSocket.EndAccept(asyncResult)) != null)
{
BeginReceive(serverSocket);
}
}
}
catch (SocketException e)
{
Console.WriteLine("Listening Socket Error:" + e.ErrorCode);
}
catch (ObjectDisposedException e)
{
Console.WriteLine("The Listening Socket has been closed");
}
}
This approach uses threads from a ThreadPool which is a good thing. While waiting for a new client to be accepted or for data to arrive no threads are used, so your code will not span 1000 threads when you have 1000 clients connected.
Just when data arrives on one socket, one free thread will be taken from the tread pool and will process your callback. When your method finishes, the thread will be returned to the pool to be available for the next data arrival or client connection.

Instead of scanning multiple ports I'm scanning only one and when port is closed my app closes

I'm trying to scan multiple ports at once using asynchronymous scanning. The problem is that I can only display the first working port and then waiting like 20 seconds my app is closing with out telling me that the port is closed.
What could be wrong with this code?
private void btnStart_Click(object sender, EventArgs e)
{
for (int port = 80; port < 100; port++)
{
ScanPort(port);
}
}
private void ScanPort(int port)
{
var client = new TcpClient();
try
{
client.BeginConnect(IPAddress.Parse("74.125.226.84"), port, new AsyncCallback(CallBack), client);
}
catch (SocketException)
{
client.Close();
}
}
private void CallBack(IAsyncResult result)
{
var client = (TcpClient)result.AsyncState;
client.EndConnect(result);
if (client.Connected)
{
this.Invoke((MethodInvoker)delegate
{
txtDisplay.Text += "open2" + Environment.NewLine;
});
}
else
{
this.Invoke((MethodInvoker)delegate
{
txtDisplay.Text += "closed2" + Environment.NewLine;
});
}
}
In your callback method, I would make sure close the connection and dispose of the TcpClient. Also TcpClient.EndConnect(IAsyncResult) can also throw exceptions. I also do not see where capturing the port number for display to the user. I would write the callback something like this.
Edit: I didn't actually compile or execute my code (sorry). I also found this other article that shows how to create a port scanner in C#, http://www.dijksterhuis.org/building-a-simple-portscanner-in-c/ There is a comment in this post stating,
There is a gotcha here : The .NET implementation of TCPClient.Close() function does not actually close the connection properly. So we need to do the additional steps of obtaining the stream representing the connection and closing this as well before calling TCPClient.Close.
private void CallBack(IAsyncResult result)
{
var client = (TcpClient)result.AsyncState;
bool connected = false;
try
{
client.EndConnect(result);
connected = client.Connected;
}
catch (SocketException)
{
}
catch (ObjectDisposedException)
{
}
finally
{
if (client.Connected)
{
client.Close();
}
client.Dispose();
}
if (connected)
{
this.Invoke((MethodInvoker)delegate
{
txtDisplay.Text += "open2" + Environment.NewLine;
});
}
else
{
this.Invoke((MethodInvoker)delegate
{
txtDisplay.Text += "closed2" + Environment.NewLine;
});
}
}

Categories