none
Tcp Server mit multiplen Clienten RRS feed

  • Frage

  • Hi,

    ich habe mir hier einen Tcp Server zusammen gebastelt.. bin noch relativ unerfahren in dem Gebiet und wollte fragen, ob (oder besser wie..) es möglich ist, das der Server auch mehrere Clients haben kann. Oder im besten Fall beliebig viele. Über ein Codebeispiel oder sogar eine Verbesserung würde ich mich sehr freuen. 

    Im Moment empfängt der Server die CPU-Last von einem Client, was dann in dem Label lblReceivedData ausgegeben wird.

    namespace Server
    {
        public partial class MainForm : Form
        {
            public MainForm()
            {
                InitializeComponent();
                this.Size = Properties.Settings.Default.Size;
                this.Location = Properties.Settings.Default.Location;
                this.WindowState = Properties.Settings.Default.WindowState;
            }

            private void btnStartServer_Click(object sender, EventArgs e)
            {
                try
                {
                    Thread obj_thread = new Thread(StartServer);
                    obj_thread.Start();
                    MessageBox.Show("Server erfolgreich gestartet", "Erfolgreich", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    btnStartServer.Text = "running...";
                    btnStartServer.Enabled = false;
                }
                catch (Exception x)
                {
                    MessageBox.Show(x.Message, "Error", MessageBoxButtons.OK);
                }
            }

            TcpListener obj_server = new TcpListener(IPAddress.Any, 6868);

            public void StartServer()
            {
                obj_server.Start();
                while (true)
                {
                    TcpClient tc = obj_server.AcceptTcpClient();
                    NetworkStream ns = tc.GetStream();
                    if (ns.ReadByte() == 2)
                    {
                        byte[] receive_data = ReadStream(ns);
                        lblReceivedData.Invoke((MethodInvoker)(() => lblReceivedData.Text = Encoding.UTF8.GetString(receive_data)));
                    }
                }
            }

            public byte[] ReadStream(NetworkStream ns)
            {
                byte[] data_buff = null;
                int b = 0;
                String buff_length = "";
                while ((b = ns.ReadByte()) != 4)
                {
                    buff_length += (char)b;
                }
                int data_length = Convert.ToInt32(buff_length);
                data_buff = new byte[data_length];
                int byte_read = 0;
                int byte_offset = 0;
                while (byte_offset < data_length)
                {
                    byte_read = ns.Read(data_buff, byte_offset, data_length + byte_offset);
                    byte_offset += byte_read;
                }
                return data_buff;
            }

            private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
            {
                Properties.Settings.Default.WindowState = this.WindowState;
                Properties.Settings.Default.Size = this.Size;
                Properties.Settings.Default.Location = this.Location;
                Properties.Settings.Default.Save();
            }
        }
    }

    Montag, 14. Januar 2019 15:27

Antworten

  • Hi,
    Dein Code arbeitet synchron bezüglich Einlesen der Daten. Nach dem AcceptTcpClient wird der nächste Client erst verarbeitet, wenn in der Schleife alle Bytes mit ReadStream eingelesen wurden. Erst danach wird der nächste Client verarbeitet.

    Wenn Du das Lesen der Daten asynchron ausführst, dann kann in der Schleife sofort mit dem nächsten AcceptTcpClient fortgesetzt werden. Die asynchrone Ausführung ist in einer neuen Thread-Instanz (für jede Anfrage eines Clients) zu organisieren. Wichtig dabei ist, wie das Ende des Lesens der Bytes "signalisiert" wird. Das kann beispielsweise eine Ereignismethode sein, wenn das Lesen in einer separaten Instanz gekapselt und diese Methode das Ereignis von dieser Instanz abonniert.


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Montag, 14. Januar 2019 17:33
  • Hi,
    es ist bestimmt übersichtlicher, das Lesen in einer separaten Klasse zu kapseln und damit auch Ereignisse zu nutzen (z.B. nachdem alle Bytes gelesen wurden).

    Alles in einer Klasse zu halten, ist möglich. Anstelle einer Ereignissteuerung sind dabei Methodenaufrufe zum Ende des Lesens der Bytes möglich. Mir wäre das aber zu unübersichtlich.


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Dienstag, 15. Januar 2019 07:10

Alle Antworten

  • Hi,
    Dein Code arbeitet synchron bezüglich Einlesen der Daten. Nach dem AcceptTcpClient wird der nächste Client erst verarbeitet, wenn in der Schleife alle Bytes mit ReadStream eingelesen wurden. Erst danach wird der nächste Client verarbeitet.

    Wenn Du das Lesen der Daten asynchron ausführst, dann kann in der Schleife sofort mit dem nächsten AcceptTcpClient fortgesetzt werden. Die asynchrone Ausführung ist in einer neuen Thread-Instanz (für jede Anfrage eines Clients) zu organisieren. Wichtig dabei ist, wie das Ende des Lesens der Bytes "signalisiert" wird. Das kann beispielsweise eine Ereignismethode sein, wenn das Lesen in einer separaten Instanz gekapselt und diese Methode das Ereignis von dieser Instanz abonniert.


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Montag, 14. Januar 2019 17:33
  • Hallo Peter, 

    vielen Dank für die Antwort! Das ist alles sehr einleuchtend, bis auf den letzten Satz. Meinst du damit, das ich das Lesen in eine eigene Klasse schreiben soll welche dann bei Ereignis "x" ausgelöst wird?

    Danke nochmal und liebe Grüße

    Dienstag, 15. Januar 2019 06:57
  • Hi,
    es ist bestimmt übersichtlicher, das Lesen in einer separaten Klasse zu kapseln und damit auch Ereignisse zu nutzen (z.B. nachdem alle Bytes gelesen wurden).

    Alles in einer Klasse zu halten, ist möglich. Anstelle einer Ereignissteuerung sind dabei Methodenaufrufe zum Ende des Lesens der Bytes möglich. Mir wäre das aber zu unübersichtlich.


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP für Developer Technologies)
    Meine Homepage mit Tipps und Tricks

    Dienstag, 15. Januar 2019 07:10