C# Winforms | I can't get values from Form in new class

49 views Asked by At

I am trying to make a Async TCP Server/Client with C# in Winforms. I have done it from the console and everything was fine.

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void StartListener_Click(object sender, EventArgs e)
        {
            AsyncSocketListener.StartListener();
        }

        public class ObjectState { 
            public Socket socket = null;
            public const int bufferSize = 1024;
            public byte[] buffer = new byte[bufferSize];
            public StringBuilder sb = new StringBuilder();
        }

        public class AsyncSocketListener { 
            public static ManualResetEvent completed = new ManualResetEvent(false);
            
            public static void StartListener()
            {
                Form1 objects = new Form1();
                byte[] bytes = new byte[1024];

                int port = int.Parse(objects.ServerPort.Text);
                IPAddress ip = IPAddress.Parse(objects.ServerIP.Text);
                IPEndPoint ep = new IPEndPoint(ip, port);
                Socket listener = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                try
                {
                    listener.Bind(ep);
                    listener.Listen(999999999);

                    while (true) { 
                        completed.Reset();
                        MessageBox.Show("Listener started: Waiting for incoming connections", "Listener started", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        listener.BeginAccept(new AsyncCallback(AcceptCallBack), listener);
                    }
                } 

                catch (Exception a) {
                    MessageBox.Show(a.Message, "Error - Listener failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }

            private static void AcceptCallBack(IAsyncResult ar) { 
                completed.Set();
                Socket listener = (Socket) ar.AsyncState;
                Socket handler = listener.EndAccept(ar);

                ObjectState state = new ObjectState();
                state.socket = handler;
                handler.BeginReceive(state.buffer, 0, ObjectState.bufferSize, 0, new AsyncCallback(ReadCallBack), state);
            }

            private static void ReadCallBack(IAsyncResult ar)
            {
                string content = String.Empty;
                ObjectState state = (ObjectState) ar.AsyncState;
                Socket handler = state.socket;
                int bytesRead = handler.EndReceive(ar);
                if (bytesRead > 0)
                {
                    state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
                    content = state.sb.ToString();
                    if (content.IndexOf("<EOF>", StringComparison.Ordinal) > -1)
                    {
                        MessageBox.Show($"Read: {content.Length} bytes from socket Data: {content}", "Socket data", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        Send(handler, content);
                    }
                    else
                    {
                        handler.BeginReceive(state.buffer, 0, ObjectState.bufferSize, 0, new AsyncCallback(ReadCallBack), state);
                    }
                }
            }

            private static void Send(Socket handler, String content)
            {
                byte[] byteData = Encoding.ASCII.GetBytes(content);
                handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
            }

            private static void SendCallback(IAsyncResult ar)
            {
                try { 
                    Socket handler = (Socket) ar.AsyncState;
                    int byteSent = handler.EndSend(ar);
                    MessageBox.Show($"Sent: {byteSent} to client", "Socket data", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    handler.Shutdown(SocketShutdown.Both);
                    handler.Close();
                }

                catch (Exception e) {
                    MessageBox.Show(e.Message, "Socket Callback Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }

        }
    }
}

When doing it with GUI, I have problems with the server. In my AsyncSocketListener class the StartListener function cannot catch the values passed in the GUI TextBoxes.

Form1 objects = new Form1();
byte[] bytes = new byte[1024];

int port = int.Parse(objects.ServerPort.Text);
IPAddress ip = IPAddress.Parse(objects.ServerIP.Text);
IPEndPoint ep = new IPEndPoint(ip, port);

Any idea what is going on here please? Why can't I get the values from the class?

I'm new to C#, sorry if this is a silly question.

1

There are 1 answers

0
jason.kaisersmith On

So if you look in your listener code at this line

Form1 objects = new Form1();

You are creating a brand new instance of the Form, and then trying to use the values from here.

You instead need to pass the reference to the original Form. So try this;

public class AsyncSocketListener 
{ 
        public static ManualResetEvent completed = new ManualResetEvent(false);

        //Amend this to accept a reference to the Form1 object                
        public static void StartListener(Form1 objects)
        {
            //Rest of code as before

Then pass the reference like this;

 private void StartListener_Click(object sender, EventArgs e)
 {
        AsyncSocketListener.StartListener(this);
 }

There are maybe a few other things you can do to improve the code (see comments) including renaming "objects" to something more meaningful, such as "form".

In fact, it would be even better to totally decouple your Form1 from your Listener class, and just pass the values into the listener such as this;

 public static void StartListener(IPAddress ip, int port)
 {         
     byte[] bytes = new byte[1024];
      IPEndPoint ep = new IPEndPoint(ip, port);
     //Rest of code as before

Pass the reference like this;

private void StartListener_Click(object sender, EventArgs e)
{
    AsyncSocketListener.StartListener(IPAddress.Parse(this.ServerIP.Text), int.Parse(this.ServerPort.Text));
}