Entwickler-Ecke

Netzwerk - löschen


PC17 - Sa 03.07.10 19:08
Titel: löschen
löschen


MoBBer - So 04.07.10 17:31

Hallo PC17,

anscheinend wird dein Socket-Objekt server automatisch verworfen wenn die Eigenschaft Connected flase gesetzt wird.
Du musst dein Socket-Objekt also immer beim Verbinden neu erstellen.


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
private void btnOpen_Click(object sender, EventArgs e)
        {
            if (!server.Connected)
                try
                {
                    server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    
                    server.Connect(ipEndPoint);
                    WriteLine("Connected to Server!");

                    var listener = new Thread(Listen);
                    listener.Priority = ThreadPriority.Lowest;
                    listener.Start();
                }
                catch (Exception exception)
                {
                    WriteLine(exception.Message);
                }
        }


PC17 - So 04.07.10 17:53

Aber wenn ich den Button klicke wird es ja eh erstellt oder wie meinst du ?
Kannst du bitte den Code so posten wie ich ihn ändern muss das ich mich wiederverbinden kann, DANKE.


MoBBer - So 04.07.10 17:55

Ich habe den geänderten Code gepostet, die markierte Zeile habe ich dort eingefügt.
Hätte ich vielleicht un Missverständnisse zu vermeiden drüber schreiben sollen. :D


PC17 - So 04.07.10 18:06

Sorry, hatte gerade den Code nicht vor mir. ;)
Danke noch mal werde ich gleich mal testen.


PC17 - So 04.07.10 18:19

Also einen Schritt bin ich weiter gekommen.
Aber wenn ich die Verbindung trenne wird der Server sofort zu gemacht und das muss man doch irgendwie verhindern können?
Jetzt kommt als Fehlermeldung:
Verbindung fehlgeschlagen: Es konnte keine Verbindung hergestellt werden, da der Zielcomputer die Verbindung verweigerte 127.0.0.1:9050

@MoBBer: Hast du dich wiederverbinden können?


MoBBer - So 04.07.10 18:27

Ja ich konnte mich wieder verbienden allerdings habe ich einfach nur den Server neu gestartet.

Das sich der Server schließt liegt daran, dass der Client eine 0 sendet wenn er die Verbindung trennt.
Und in dem Fall wird das Programm einfach bis zum Schluss abgearbeitet.

Du müsstest dir eine Endlosschleife bauen die die Anfragen zum Verbinden entgegen nimmt und die einzelnen Threads zum schreiben startet.


PC17 - So 04.07.10 18:35

Ja so kann ich mich auch wieder verbinden. Aber ich möchte ja bei dem einen Server die Verbindung trennen und die Verbundung zu einen anderen aufbauen und später wieder zu den alten zurück verbinden. Also einfach trennen und wieder verbinden.

Meinst du das ich einen Endlossschleife über den Server machen soll(while Schleife)?


MoBBer - So 04.07.10 18:59

Ja du musst bei deinem Server die Verbindungslogik in eine Endlosschleife schreiben und in der Methode Listen darfst du den Listener nicht stoppen.



Main-Methode, die markierten Zeilen sind hinzuzufügen:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
data = new byte[1024];
var localAddress = IPAddress.Any;
tcpListener = new TcpListener(localAddress, 9050);
tcpListener.Start();
Console.WriteLine("I'am the TCP Server!");
Console.WriteLine("Waiting for a client...");

while (true)
{

    tcpClient = tcpListener.AcceptTcpClient();
    networkStream = tcpClient.GetStream();

    data = "Welcome to TCP Server!".ToByteArray();
    networkStream.Write(data, 0, data.Length);

    var listener = new Thread(Listen);
    listener.Priority = ThreadPriority.Lowest;
    listener.Start();
}


Listen-Methode, markierte Zeile ist zu löschen:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
while (true)
{
    data = new byte[1024];
    received = networkStream.Read(data, 0, data.Length);
    if (received == 0)
       break;

    string get = Encoding.ASCII.GetString(data, 0, received);
    var send = get.ToByteArray();
    Console.WriteLine("Received from TCP Client: " + get);
    networkStream.Write(send, 0, send.Length);
}

networkStream.Close();
tcpClient.Close();
tcpListener.Stop();


So läuft der Server immer weiter und du kannst dich munter drauf verbinden und trennen.


Christian S. - So 04.07.10 19:00

Ich hab ja von dem Netzwerk-Kram wenig Ahnung, aber produziert die Endlos-Schleife nicht ne Menge Threads, die nie gestoppt werden? :gruebel:


MoBBer - So 04.07.10 19:08

Ja das stimmt man sollte den erstellten Thread am ende des Chats wieder beenden.

Allerdings wird ein neuer Thread ja immer nur erstellt wenn sich ein Client verbindet und momentan kann sich nur ein Client verbinden.


Christian S. - So 04.07.10 19:17

Ich hab mir das jetzt mal genauer angesehen und denke, die Erstellung von Threads in einer Endlos-Schleife ist nicht nötig. Um das Beenden des Servers zu verhindern, reicht doch ein einfaches Console.ReadLine().

Der ganze Sinn von Threads ist doch gerade, ein Programm nicht zu blockieren. Ein Programm dadurch zu blockieren, dass man am laufenden Band Threads erstellt mutet irgendwie sehr komisch an.

So scheint es zu funktionieren:

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:
    private static byte[] data;
    private static NetworkStream networkStream;
    private static int received;
    private static TcpClient tcpClient;
    private static TcpListener tcpListener;
    private static volatile bool running;

    public static void Main()
    {
        data = new byte[1024];
        var localAddress = IPAddress.Any;
        tcpListener = new TcpListener(localAddress, 9050);
        tcpListener.Start();
        Console.WriteLine("I'am the TCP Server!");
        Console.WriteLine("Waiting for a client...");

        tcpClient = tcpListener.AcceptTcpClient();
        networkStream = tcpClient.GetStream();
        
        data = "Welcome to TCP Server!".ToByteArray();
        networkStream.Write(data, 0, data.Length);

        var listener = new Thread(Listen);
        listener.Priority = ThreadPriority.Lowest;
        running = true;
        listener.Start();


        Console.ReadLine();
        running = false;

    }

    static void Listen()
    {
        
        while (running)
        {
            data = new byte[1024];
            received = networkStream.Read(data, 0, data.Length);
            if (received > 0)
            {

                string get = Encoding.ASCII.GetString(data, 0, received);
                var send = get.ToByteArray();
                Console.WriteLine("Received from TCP Client: " + get);
                networkStream.Write(send, 0, send.Length);
            }
        }
        networkStream.Close();
        tcpClient.Close();
        tcpListener.Stop();
    }


PC17 - So 04.07.10 19:21

Okay, danke für eure Hilfe

Wenn einige Threads endlos dahin laufen ist es auch egal mehr wie zu 4 Server werde ich mich nicht verbinden.


MoBBer - So 04.07.10 19:36

@ Christian S.: so funktioniert das nicht die Listen-Methode an sich soll nicht unendlich weiter laufen.
Deine Umstellung auf "if (received > 0)" hat zur folge das sich ein Client nicht mehr von Server trennen kann.

Es geht darum das der TCPListener immer weiter laufen muss, damit sich der Client nach dem Trennen nocheinmal verbinden kann und genau das bewirkt meine Endlosschleife.

In meiner Endlosschleife werden nicht unzählige Threads erstellt da die Zeile

"tcpClient = tcpListener.AcceptTcpClient();"

bewirkt, dass die Ausführung stoppt bis sich ein Client bei dem Server meldet. Die Endlosschleife pausiert so zu sagen.

@PC17: Du sollest mal dieses Tutorial [http://msdn.microsoft.com/de-de/library/bb979208.aspx] durcharbeiten und auch deinen Chat-Server/Client anpassen

mfg MoBBer


Christian S. - So 04.07.10 19:40

Ja, user profile iconKha wies mich auch gerade drauf hin. Das mit dem AcceptTcpClient habe ich übersehen.

Aber ist es nicht sinnvoll, einen Verbindung zu halten, so lange sie gebraucht wird, anstatt immer wieder neu zu verbinden? :gruebel:


MoBBer - So 04.07.10 19:42

Ja sicher, aber "received == 0" bedeutet, dass der Client die Verbindung getrennt hat und damit man die Verbindung wiederaufnehmen kann muss der TCPListener weiterlaufen und auf Clients warten. Desweiteren ist das der Grundstein damit später auf seinem Server mehrere Leute gleichzeitig angemeldet sein können und mit einander chatten können.


Christian S. - So 04.07.10 19:45

Ah, okay. :idea:

Ich glaube, ich warte mit dem Netzwerk-Kram, bis der ganze Schleifenkram weggekapselt ist. Bei Windows muss man sich ja auch nicht mehr mit der Schleife zur Nachrichtenverarbeitung rumschlagen :mrgreen:


Kha - So 04.07.10 20:20

Kein Problem, ich biete Rekursion an :mrgreen: .
Es sollte möglich sein, die Kommunikation über BeginAcceptTcpClient, BeginRead und BeginWrite komplett asynchron zu gestalten, wie ich das hier [http://c-sharp-forum.de/viewtopic.php?t=87786] schon einmal mit Accept versucht habe. Damit wird also nur ein Thread benötigt, wenn sich ein neuer Client verbindet oder eine Anfrage bearbeitet wird. Wartende Threads gibt es überhaupt nicht mehr.

Muss mir mal anschauen, ob die TPL das noch etwas hübscher hinbekommen würde :gruebel: .


Kha - Mo 05.07.10 22:35

Die erste Version ist keine großartige Verbesserung, aber die zweite muss sich imo nicht einmal hinter den Async Expressions von F# verstecken.


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:
static class TcpListenerEx
{
  public static Task<TcpClient> AcceptTcpClientAsync(this TcpListener self)
  {
    return Task<TcpClient>.Factory.FromAsync(self.BeginAcceptTcpClient, self.EndAcceptTcpClient, state: null);
  }
}

void AcceptClients()
{
  listener.AcceptTcpClientAsync().ContinueWith(client => {
      HandleClient(client.Result);
      AcceptClients();
  });
}

void HandleClient(TcpClient tcpClient)
{
  Stream stream = tcpClient.GetStream();
  var buffer = new byte[140];
  // Aus ParallelExtensionExtras, http://blogs.msdn.com/b/pfxteam/archive/2010/04/04/9990342.aspx
  stream.ReadAsync(buffer, 0, buffer.Length).ContinueWith(read => {
    if (read.Result > 0)
      stream.WriteAsync(buffer.Reverse().ToArray(), 0, buffer.Length).ContinueWith(_ =>
        HandleClient(tcpClient)
      );
  });
}

void AcceptClients2()
{
  // Ebenfalls ParallelExtensionExtras, siehe http://blogs.msdn.com/b/pfxteam/archive/2009/06/30/9809774.aspx
  Task.Factory.Iterate(this.AcceptClients2Loop());
}

IEnumerable<Task> AcceptClients2Loop()
{
  while (true)
  {
    var client = listener.AcceptTcpClientAsync();
    yield return client;
    Task.Factory.Iterate(HandleClient2(client.Result));
  }
}

IEnumerable<Task> HandleClient2(TcpClient tcpClient)
{
  Stream stream = tcpClient.GetStream();
  var buffer = new byte[140];

  while (true) {
    var read = stream.ReadAsync(buffer, 0, buffer.Length);
    yield return read;
    if (read.Result == 0)
      break;
    yield return stream.WriteAsync(buffer.Reverse().ToArray(), 0, buffer.Length);
  }
}


Achja, alles ungetestet ;) .


PC17 - Di 13.07.10 20:26

Habe da noch einen anderen Server and Client gefunden ist leider nur ein code und habe ihn noch nicht getestet und jetzt stehe ich beim TCPListener an.

Das ist die Listen Methode von dem oben genannten Client:

C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
private void Listen()
        {
            var recv = server.Receive(data);
            stringData = Encoding.ASCII.GetString(data, 0, recv);
            WriteLine(stringData);

            while (server.Connected)
            {
                data = new byte[1024];
                recv = server.Receive(data);
                stringData = Encoding.ASCII.GetString(data, 0, recv);
                WriteLine("Received from Server: " + stringData);
            }
            WriteLine("Disconnecting from server...");
            server.Close();
        }




Möchte einfach die neue Methode StartListen() zu der alten Listen() hinzufügen das ich mich über die Methode Listen verbinden und halt dann der alte Server and Client läuft und auch die Methode RunClient ausgeführt wird.
Ich bringe es dann nicht zusammen das ich socketForServer,IPEndPoint vom neuen Client im alten einbaue. Vl kann mir jemand helfen, falls es noch fragen gibt bitte melden.

MfG PC17


PC17 - Do 15.07.10 11:20

löschen


PC17 - Fr 16.07.10 08:45

Eine Frage habe ich noch zu diesem Server and Client.
Ich kann ja Nachrichten zum Server und vom Server zum Client senden.
Gibt es da eine Begrenzung der Größe?
Lasse mir viel text vom Server zum Client schicken.

Wenn ich dann einen Breakpoint setzt steht in der Variable, diese Varibale will ich mir zurück senden lassen:
{Text = "((System.Windows.Forms.TextBox)(textBox1)).Text" hat eine Ausnahme vom Typ "Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException" verursacht.}


PC17 - So 18.07.10 10:26

Danke MoBBer für deine Hilfe.

Habe jetzt mein Problem gelöst.