Autor Beitrag
JoKaBo
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 157



BeitragVerfasst: Do 22.08.13 14:51 
Hallo,

seit Kurzen beschäftige ich mich in C# mit der Server Programmierung. Jetzt wo ich gerne mal das ganze in eine schöne Windows Form packet möchte klappt es leider nicht mehr so, wie ich es mir wünsche.

Das Programm Startet ganz normal. Dann Drücke ich auf den Start Button, worauf cmdStart_Click aufgerufen wird.

Nach dem das Passiert ist, tut sich in dem Programm Garnichts mehr. Das Programm wird weder von Windows versucht zu Beenden noch kommt eine Exeption / Fehler Meldung.

Ich hoffe ihr könnt mir da helfen, da ich nicht mehr weiter weiß.

Liebe Grüße und Danke im voraus.

JoKaBo

Code:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
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.Sockets;
using System.Net;
using System.Threading;
using Extensions;


namespace ServerAndClientWinForms
{
    public partial class Server : Form
    {
        static TcpListener tcpListener;        
        private static NetworkStream networkStream;
        private static Socket socketForClient;

        public Server()
        {
            InitializeComponent();
        }

        private void Server_Load(object sender, EventArgs e)
        {
        }

        private void WaitForClients()
        {
        }

        private void cmdStart_Click(object sender, EventArgs e)
        {
            var ipAdress = IPAddress.Parse("127.0.0.1");
            int port = 9050;

            tcpListener = new TcpListener(ipAdress, port);

            tcpListener.Start();

            socketForClient = tcpListener.AcceptSocket();
            networkStream = new NetworkStream(socketForClient);    

           
            WriteConsole("Server wurde gestartet");
            WriteConsole("Server IP: " + ipAdress);
            WriteConsole("Server Port: " + port.ToString());

            int numberOfClientsYouNeedToConnect = 10;
            for (int i = 0; i < numberOfClientsYouNeedToConnect; i++)
            {
                Thread newThread = new Thread(new ThreadStart(Listeners));
                newThread.Start();
            }
            
        }

        private void cmdStop_Click(object sender, EventArgs e)
        {
            tcpListener.Stop();
            ///socketForClient.Disconnect();
        }

        private void Listeners()
        {
            if (socketForClient.Connected)
            {
                WriteConsole("Client:" + socketForClient.RemoteEndPoint + " connected to server.");
                
                System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
                System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream);

                while (true)
                {
                    string theString = streamReader.ReadLine();
                    WriteConsole("Client " + socketForClient.RemoteEndPoint + "send a message: " + theString + "\n");
                    if (theString == "exit")
                        break;
                }

                streamReader.Close();
                networkStream.Close();
                streamWriter.Close();
            }
            socketForClient.Close();
            WriteConsole("Press any key to exit from server program");
            Console.ReadKey();
        }

        private void WriteConsole (string text) 
        {
            rtbConsole.Text += text + "\n";
        }
    }
}
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4796
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Do 22.08.13 16:27 
Hallo,

tcpListener.AcceptSocket() blockiert solange kein Client sich angemeldet hat.
Da WinForms ereignisorientiert arbeitet, darfst du also nicht einfach einen Blocker einbauen.
Ähnlich wie du auch für die Clients einen eigenen Thread startest, mußt du dies auch für den Listener machen.

Aber du hast m.E. noch einen groben Fehler in deinem Programm. Du startest bisher 10 Threads, um mit einen ClientSocket zu kommunizieren. Du solltest eher den Listener in einer Schleife laufen lassen und für jeden ClientSocket einen eigenen Thread erzeugen.

Für diesen Beitrag haben gedankt: JoKaBo
JoKaBo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 157



BeitragVerfasst: Do 22.08.13 17:20 
Danke für die schnelle Antwort. Ich teste das gleich mal!

Zitat:
Aber du hast m.E. noch einen groben Fehler in deinem Programm. Du startest bisher 10 Threads, um mit einen ClientSocket zu kommunizieren. Du solltest eher den Listener in einer Schleife laufen lassen und für jeden ClientSocket einen eigenen Thread erzeugen.


Nein, später möchte ich das erweitern, so das aus einer Konfiguratuions Datei der die Anzahl der "Slotz" angegeben werden kann.

LG
JoKaBo

EDIT:

tcpListener.AcceptSocket() Mit was muss ich das den ersetzten, also was muss ich dann dahin machen. ?
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4796
Erhaltene Danke: 1059

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 23.08.13 11:57 
Hallo,

habe dein "Edit" jetzt erst gelesem.

Wie ich schon schrieb;
Th69 hat folgendes geschrieben:
Ähnlich wie du auch für die Clients einen eigenen Thread startest, mußt du dies auch für den Listener machen.

Also die Methode in einem eigenen Thread ausführen lassen:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
private void cmdStart_Click(object sender, EventArgs e)
{
   Thread newThread = new Thread(new ThreadStart(WaitForClients));
   newThread.Start(); 
}

private void WaitForClients()
{
   var ipAdress = IPAddress.Parse("127.0.0.1");
   int port = 9050;

   tcpListener = new TcpListener(ipAdress, port);

   tcpListener.Start();

   while (true// <- oder andere Laufzeitbedingung, z.B. Server.Connected
   {
     // hier nun lokale Variablen benutzen, anstatt 'static' !!!
     Socket socketForClient = tcpListener.AcceptSocket();
     NetworkStream networkStream = new NetworkStream(socketForClient);

     // Start Thread ... (nun am besten mit ParameterizedThreadStart)
   }
}

Für diesen Beitrag haben gedankt: JoKaBo
JoKaBo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 157



BeitragVerfasst: Mo 26.08.13 19:47 
Hey,

sorry das ich mich jetzt erst melde, hatte viel mit Arbeit und Schule zu tun.

Erstmal vielen Dank für die schnelle Antwort.

Leider bekomme ich jetzt einen anderen Fehler, und ich habe auch mit Googlen nichts gefunden. Vielleicht liegt es daran, wie ich Google.
Na ja, vielleicht könnt ihr mir dabei ja helfen. :)

Title: "InvalidOpertaionExeption wurde nicht behandelt".
Message: "Ungültiger threadübergreifender Vorgang: Der Zugriff auf das Steuerelement rtbConsole erfolgte von einem anderen Thread als dem Thread, für den es erstellt wurde."

Hier nochmal der ganze Code:

ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
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.Sockets;
using System.Net;
using System.Threading;
using Extensions;


namespace ServerAndClientWinForms
{
    public partial class Server : Form
    {
        static TcpListener tcpListener;
        private static NetworkStream networkStream;
        private static Socket socketForClient;

        public Server()
        {
            InitializeComponent();
        }

        private void Server_Load(object sender, EventArgs e)
        {
        }

        private void cmdStart_Click(object sender, EventArgs e)
        {
            Thread newThread = new Thread(new ThreadStart(WaitForClients));
            newThread.Start();
        }

        private void WaitForClients()
        {
            var ipAdress = IPAddress.Parse("127.0.0.1");
            int port = 9050;

            tcpListener = new TcpListener(ipAdress, port);

            tcpListener.Start();
            WriteConsole("Server Startet");

            WriteConsole("Server wurde gestartet. Server wurde mit IP: " + ipAdress.ToString() + "und dem Port: " + port.ToString() + "Gestartet");
            while (true// <- oder andere Laufzeitbedingung, z.B. Server.Connected
            {
                // hier nun lokale Variablen benutzen, anstatt 'static' !!!
                Socket socketForClient = tcpListener.AcceptSocket();
                NetworkStream networkStream = new NetworkStream(socketForClient);

                // Start Thread ... (nun am besten mit ParameterizedThreadStart)
            }
        }

        private void cmdStop_Click(object sender, EventArgs e)
        {
            tcpListener.Stop();
            ///socketForClient.Disconnect();
        }

        private void Listeners()
        {
            if (socketForClient.Connected)
            {
                WriteConsole("Client:" + socketForClient.RemoteEndPoint + " connected to server.");

                System.IO.StreamWriter streamWriter = new System.IO.StreamWriter(networkStream);
                System.IO.StreamReader streamReader = new System.IO.StreamReader(networkStream);

                while (true)
                {
                    string theString = streamReader.ReadLine();
                    WriteConsole("Client " + socketForClient.RemoteEndPoint + "send a message: " + theString + "\n");
                    if (theString == "exit")
                        break;
                }

                streamReader.Close();
                networkStream.Close();
                streamWriter.Close();
            }
            socketForClient.Close();
            WriteConsole("Press any key to exit from server program");
            Console.ReadKey();
        }

        private void WriteConsole(string text)
        {
            rtbConsole.Text += text + "\n";
        }
    }
}


Ich hoffe, das ihr mir dabei nochmal helfen könnt.

Lieben Gruß
JoKaBo
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 26.08.13 19:58 
Zumindest deine WriteConsole Methode greift auf die UI zu. Auf die UI darf man nur aus dem Hauptthread aus zugreifen. Heißt in der WriteConsole Methode musst du den Aufruf in den Hauptthread zurück synchronisieren. Dabei hilft die Invoke Methode des betroffenen Controls (oder der Form)

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
private void WriteConsole (string text) 
{
    if (rtbConsole.InvokeRequired)
       rtbConsole.Invoke(new Action(() => this.WriteConsole(text)));
    else
       rtbConsole.Text += text + "\n";
}


Zuletzt bearbeitet von Ralf Jansen am Mo 26.08.13 20:32, insgesamt 1-mal bearbeitet

Für diesen Beitrag haben gedankt: JoKaBo
JoKaBo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 157



BeitragVerfasst: Mo 26.08.13 20:13 
Hey,

danke für die Antwort. Hier kommt folgender Fehler:

ausblenden Quelltext
1:
"lambda-Ausdruck" kann nicht in den Typ "System.Delegate" konvertiert werden, da dies kein Delegattyp ist.					


Lieben Gruß
JoKaBo
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 26.08.13 20:33 
Sorry. Hab den Code korrigiert.

Für diesen Beitrag haben gedankt: JoKaBo
JoKaBo Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 157



BeitragVerfasst: Mo 26.08.13 20:47 
Hey,

ich danke euch beiden, endlich Klappt das!

Eine sache, würde ich gerne noch wissen.

Ich will den Server auch Stoppen können (Siehe cmdStop).

tcpListener.Stop(); Wenn ich das mache, kommt Logischer weise eine "SocketExeption": "Ein Blockierungsvorgang wurde durch einen Aufruf von WSACancelBlockingCall unterbrochen"

Wie mache ich das richtig ?

LG
JoKaBo
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4708
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mo 26.08.13 21:06 
Du versucht den im nebenläufigen Thread erzeugten TcpListener aus dem Hauptthread zu stoppen. Das ist ebenfalls nicht erlaubt das muss aus dem gleichen Thread erfolgen.

Close den Listener auch in der WaitForClients Methode. Am besten vielleicht in dem du den Listener in einen using Block kapselst. Und in deiner Stop Methode Abort(e) dann den Thread anstatt nur den Listener. War eh Mist wie das gerade läuft. Du hättest den Listener geschlossen aber den Thread weiterrotieren lassen.

Für diesen Beitrag haben gedankt: JoKaBo