0

I'm trying to implement a SCS framework server with WinForms in C# but I am having issues making it work. The server standalone works fine when using it in the Main method (no WinForms). I have a client-sided and a server-sided sample code from the SCS framework that I'm trying to implement in WinForms together with some of my own code. It all went well until I decided to try and use WinForms aswell (I had to move the server code to a class of it's own).

I am not getting any errors when I am starting the server, however I can't connect with the client anymore (worked before I moved the server to a class of its own). Client gets System.Net.Sockets.SocketException. On the server-side, I get the error System.InvalidOperationException when the client is trying to connect.

This is my Form1.cs:

using System;
using System.Windows.Forms;

namespace Server_Test
{
    public partial class Form1 : Form
    {
        public static Form1 Self;
        Server server = new Server();

        public Form1()
        {
            InitializeComponent();
            Self = this;
        }

        public void rtb1Text(string text)
        {
            richTextBox1.AppendText(text);
        }

        public void rtb2Text(string text)
        {
            richTextBox2.Text = text;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (button1.Text.EndsWith("Start"))
            {
                button1.Text = "Stop";
                server.ServerInit();
            }
            else if (button1.Text.EndsWith("Stop"))
            {
                button1.Text = "Start";
                // Does nothing atm
            }
        }
    }
}

And this is my Server.cs

using System;
using Hik.Communication.Scs.Communication.EndPoints.Tcp;
using Hik.Communication.Scs.Communication.Messages;
using Hik.Communication.Scs.Server;

namespace Server_Test
{
    class Server
    {
        public void ServerInit()
        {
            // Create a server that listens 10085 TCP port for incoming connections
            var server = ScsServerFactory.CreateServer(new ScsTcpEndPoint(10085));

            // Register events of the server to be informed about clients
            server.ClientConnected += Server_ClientConnected;
            server.ClientDisconnected += Server_ClientDisconnected;

            // Start the server
            server.Start(); 

            // Form1.Self.rtb1Text("Server has been started successfully.\n");
            Console.WriteLine("Server has been started successfully.\n");
        }

        static void Server_ClientConnected(object sender, ServerClientEventArgs e)
        {
            Form1.Self.rtb1Text("A new client with ID: " + e.Client.ClientId + " has connected.\n");

            // Register to MessageReceived event to receive messages from new client
            e.Client.MessageReceived += Client_MessageReceived;
        }

        static void Server_ClientDisconnected(object sender, ServerClientEventArgs e)
        {
            Form1.Self.rtb1Text("A client is disconnected! Client Id = " + e.Client.ClientId + "\n");
        }

        static async void Client_MessageReceived(object sender, MessageEventArgs e)
        {
            var message = e.Message as ScsTextMessage; // Server only accepts text messages
            if (message == null)
            {
                return;
            }

            //Get a reference to the client
            var client = (IScsServerClient)sender;

            Form1.Self.rtb1Text("Client (ID:" + client.ClientId + ") sent a request: " + message.Text + "\n");

            switch (message.Text)
            {
                case "api":
                    HttpPost httpPost = new HttpPost();
                    var apiResponse = await httpPost.SendPost("robot_info");

                    //Send reply message to the client
                    client.SendMessage(
                        new ScsTextMessage(
                            apiResponse,
                            message.MessageId //Set first message's id as replied message id
                            ));
                    break;
                default:
                    break;
            }
        }
    }
}

My guess is that I'm doing something wrong when creating a new instance of the Server class and how I'm initializing/starting the server. Might be something else though, I've tried debugging but it didn't make me any smarter.

Any ideas?

lemonslayer
  • 171
  • 10
  • Remove all static stuff, starting from this: `public static Form1 Self;`. This is not a Console app. Your Form handler could implement an Interface (e.g., IMessageHandler), which describes what methods to call, with what arguments. You can then pass `this` to `ServerInit(IMessageHandler handler)`, so the Server class knows what method has to call -- When you add and event handler to `e.Client` when it connects, you also have to remove it when it disconnects – Jimi Dec 20 '22 at 11:57
  • I don't know this library, but I assume these events are raised in ThreadPool Threads, so you have to marshal the calls to the UI Thread. You can use `SynchronizationContext.Current` to `Post()` to the UI Thread, or use `BeginInvoke()`, to set properties of Controls -- Probably better if you pass an `IProgress` delegate to the Server class, so you don't need anything else. The Server can just call the `Report()` method of the `Progress` object, the Form knows what to do with the data (so the Server, as it should be, doesn't need to know anything about the class that initialized it) – Jimi Dec 20 '22 at 12:18

0 Answers0