nGX
nGX

Reputation: 1068

Threading in GUI

I have a tool that does a port scan, the problem I am running into is that when the endpoint is unreachable the GUI freezes till it gets some sort of error. I have tried creating a thread but I am not too familiar with how to do it. Can someone show me how?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace PortScan
{
    public partial class Form1 : Form
    {


        public Form1()
        {
            InitializeComponent();
            timeTextBox.Text = "2000";
        }

        private void button1_Click(object sender, EventArgs e)
        {
            ThreadStart threadStart = GetPortStatus;
            threadStart.BeginInvoke(null, null);
            GetPortStatus();
        }

        private void GetPortStatus()
        {
            button1.Enabled = false;
            var currentIP = ipaddressTextBox.Text;
            int anInteger;
            anInteger = Convert.ToInt32(portTextBox.Text);
            anInteger = int.Parse(portTextBox.Text);

            IPAddress IP = IPAddress.Parse(currentIP);
            IPEndPoint EndPoint = new IPEndPoint(IP, anInteger);

            Socket query = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            //Console.WriteLine("Blocking: {0}", query.Blocking);

            //resultsTextBox.Text = currentIP + ":" + anInteger + " is blocked: " + query.Blocking;
            //resultsTextBox.Text += Environment.NewLine + currentIP + ":" + anInteger + " is blocked: " + query.Blocking;
            try
            {
                query.Connect(EndPoint);
                resultsTextBox.Text += "Connected to " + EndPoint + Environment.NewLine;
            }
            catch (SocketException i)
            {
                //Console.WriteLine("Problem connecting to host");
                //Console.WriteLine(e.ToString());
                resultsTextBox.Text += "Cannot connect to " + EndPoint + ", port maybe blocked" + Environment.NewLine;
                query.Close();
                button1.Enabled = true;
                return;
            }
            //if (InvokeRequired)
            //{
            //    Invoke(new MethodInvoker(Close));
            //}
            //else
            //{
            //    Close();
            //}

            query.Close();
            button1.Enabled = true;
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
            if (autoCheckBox.Checked == true)
            {
                button1_Click(sender, e);
            }
            else
            {
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }
}

Upvotes: 0

Views: 293

Answers (3)

Matthias
Matthias

Reputation: 16209

The first problem, is that Socket.Connect() is a blocking method. It'll not return until the connection succeeded/refused. You can use the asynchronous methods instead BeginConnect() and EndConnect(). But this is not the real problem, because you are already using a new thread.

The second problem, is that you can't update your GUI from an other thread than the main thread.

        Invoke(new MethodInvoker(() =>
        {
               ... // GUI updates (like your resultsTextBox)
        }));

If you do not like the Invoke stuff, you can use a BackgroundWorker and its ReportProgress method + ProgressChanged event.

And @Hmm is right, since you do not use a new Thread object, the method is called on the GUI thread. But you need to Invoke updates then, as I described above.

EDIT

Btw, the cleanest solution would be to use AOP (OnGuiThreadAttribute) in order to fulfill seperation of concerns.

Upvotes: 1

Robert
Robert

Reputation: 2282

    private void button1_Click(object sender, EventArgs e)
    {
        ThreadStart threadStart = GetPortStatus;
        threadStart.BeginInvoke(null, null);
        GetPortStatus();
    }

Should be:

    private void button1_Click(object sender, EventArgs e)
    {
        ThreadStart threadStart = new ThreadStart(GetPortStatus);
        Thread name = new Thread(threadStart);
        name.Start();
    }

You pass a delegate of the function you wish to invoke in the threadstart constructor. Threadstart represents a method that executes on a thread.

Upvotes: 1

John Jeffery
John Jeffery

Reputation: 1020

If you are building a Windows Forms application that needs to perform tasks on a separate thread, I would recommend you use the BackgroundWorker component. There is an excellent tutorial on how to use this component at http://www.dotnetperls.com/backgroundworker.

Upvotes: 1

Related Questions