Laden...

Prüfen, ob ein TcpClient noch verbunden ist

Erstellt von idontwantaname vor 16 Jahren Letzter Beitrag vor 16 Jahren 19.199 Views
I
idontwantaname Themenstarter:in
86 Beiträge seit 2006
vor 16 Jahren
Prüfen, ob ein TcpClient noch verbunden ist

Hallo!

Ich habe folgendes Problem, und zwar schreibe ich eine Server-Anwendung die den TcpListener verwendet und TcpClients entgegennimmt. Das Problem, welches ich hierbei habe ist, dass es mir zur Zeit nicht möglich ist, zu erkennen, ob der Client noch verbunden ist oder nicht.
Habt ihr eine Möglichkeit, wie ich dies prüfen kann?

Schon mal vielen Dank im Vorraus!
Lg oli

I
1.739 Beiträge seit 2005
vor 16 Jahren

Meinst du den Abschied des Gegenüber mittels FIN oder den Bruch der Connection(phys.)?

I
idontwantaname Themenstarter:in
86 Beiträge seit 2006
vor 16 Jahren

Tut mir Leid, ich weiß leider nicht, was FIN ist, aber eigentlich meine ich wenn der Client die Verbindung trennt, aber dies nicht zuerst über ein Packet ankündigt.

I
1.739 Beiträge seit 2005
vor 16 Jahren

FIN ist ein Signal -> Bedeutung = Bye. Heisst: Vedrbindung angenommen, irgendwas getan(oder nicht) und Verbindung beendet(Socket.Close als Entsprechung). In demFall wird ein FIN gesendet(Benutze Etheral oder einen anderen Packetviewer um es zu sehen). Blöd ist nur das der .Net Client das nicht meldet(zumindest nicht direkt).
Lösung ist das pollen des Readers auf nicht in der MSDN-beschriebenen Weise. Hatte dieses Problem erst vor 3 - 4 Monaten gelöst, muss erst nachschauen.
Es ist feststellbar im Read, weiss nur gerad nicht wie(nachschauen halt, Auswendig hab ich es gerade nicht).

I
idontwantaname Themenstarter:in
86 Beiträge seit 2006
vor 16 Jahren

Könntest du das vielleicht nachsehen wie das geht?
Weil das wäre echt wichtig für mich!

Vielen Dank jetzt schon mal für deine bisherige und noch zukünftige Mühe 🙂
Lg oli

I
idontwantaname Themenstarter:in
86 Beiträge seit 2006
vor 16 Jahren

Kann mir denn niemand das einm wenig näher erklären?
Ich wäre euch echt sehr dankbar!

Lg oli

4.506 Beiträge seit 2004
vor 16 Jahren

Hallo idontwantaname,

ich bin vor Ewigkeiten zu dem Entschluss gekommen, dass es keine zuverlässige Methode gibt, einen TCP/IP Abbruch mitzubekommen. Einzig was hilft ist, dass bei einem "Read" oder bei einem "Write" ein Try-Catch darum zu bauen und im Fehlerfall einen erneuten Verbindungsaufbau zu probieren.

Es gibt auch praktische keine Möglichkeit festzustellen, wenn auf der Gegenseite einfach so jemand das Kabel abzieht. Es gibt hier keine Möglichkeit zu intervenieren oder informiert zu werden. Schon allein deshalb ist Try-Catch eine vernünftige Lösung.

Zusatzinfo:
Ich habe damals auch schon festgestellt, dass MS-Windows2000 zusammen mit Win2003 Server eine "kranke" TCP/IP Verbindung aufbaut, bei der nicht alle gewollten Verbindungsabbrüche gesenset wurden (Known MS-Bug).

Grüße
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

I
idontwantaname Themenstarter:in
86 Beiträge seit 2006
vor 16 Jahren

Hm, das was du sagst, ist schade :-\
Zur Zeit lese ich so Daten aus, dass eine while-Schleife läuft und wenn der NetworkStream bei DataAvailable true zurückgibt, Daten auslese. Wenn es jedoch zu einem Verbindungabbruch kommt, so wird der Stream wohl immer false bei DataAvailable ausgeben.

Wie kann ich also die Sache angehen, um den Vebindungsabbruch zu erkennen?

Lg oli

B
1.529 Beiträge seit 2006
vor 16 Jahren

Einen eigenen TimeOut implementieren.

I
1.739 Beiträge seit 2005
vor 16 Jahren

Original von Borg
Einen eigenen TimeOut implementieren.

Ja genau, wenn man weiss wie...
Den Timeout muss man bemerken. Zu meiner Schande - ich hab die Lösung nur immer noch nicht parat.
(Ist aber eigentlich simpel, ...)

_ mea culpa, vertröste auf später...
(trennen ist das derzeitige problem)

Edit: (Stick vergessen)

I
idontwantaname Themenstarter:in
86 Beiträge seit 2006
vor 16 Jahren

Also ich habe das Problem jetzt selbst gelöst.

Hier die wichtigen Teile:

try
{
  SocketError error;
  int size = client.Receive(buffer, 0, bufferSize, SocketFlags.None, out error);
  if (error == SocketError.Success && size > 0)
  { }
  else
  {
    // Disconnect
  }
}
catch
{
  // Disconnect
}

Hier ist meine Lösung gekapselt in einer Klasse mit Threading und allem drumherum:

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SocketTest
{
    public class TcpServer
    {
        /// <summary>
        /// When a client connects to the server.
        /// </summary>
        public delegate void ClientConnected(Socket client);

        /// <summary>
        /// When a client connects to the server.
        /// </summary>
        public event ClientConnected OnClientConnected;

        /// <summary>
        /// When a client sends data.
        /// </summary>
        public delegate void DataReceived(Socket client, byte[] data);

        /// <summary>
        /// When a client sends data.
        /// </summary>
        public event DataReceived OnDataReceived;

        /// <summary>
        /// When a client disconnects.
        /// </summary>
        public delegate void ClientDisconnected(Socket client);

        /// <summary>
        /// When a client disconnects.
        /// </summary>
        public event ClientDisconnected OnClientDisconnected;

        /// <summary>
        /// The socket on which the tcp server is based on.
        /// </summary>
        private Socket socket;

        /// <summary>
        /// The server's port.
        /// </summary>
        private int port;

        /// <summary>
        /// The buffer size.
        /// </summary>
        private int bufferSize;

        /// <summary>
        /// The thread in which the server listens for incoming connections.
        /// </summary>
        private Thread listeningThread;

        /// <summary>
        /// A list of threads in which interaction with client is handled.
        /// </summary>
        private List<Thread> clientThreads;

        /// <summary>
        /// Defines if the server is active or not.
        /// </summary>
        private bool active;

        /// <summary>
        /// Defines if the server is active or not.
        /// </summary>
        public bool Active
        {
            get
            {
                return active;
            }
        }

        /// <summary>
        /// Creates a new tcp server on a certain port.
        /// </summary>
        /// <param name="port">The port on which the server should run.</param>
        /// <param name="bufferSize">The size of the buffer.</param>
        public TcpServer(int port, int bufferSize)
        {
            this.port = port;
            this.bufferSize = bufferSize;

            clientThreads = new List<Thread>();
        }

        /// <summary>
        /// Starts the server.
        /// <param name="backlog">The max. number of outstanding connections.</param>
        /// </summary>
        public void Start(int backlog)
        {
            active = true;
            try
            {
                IPEndPoint endpoint = new IPEndPoint(new IPAddress(0), port);
                socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket.Bind(endpoint);
                socket.Listen(backlog);

                listeningThread = new Thread(new ThreadStart(listen));
                listeningThread.Start();
            }
            catch
            {
                active = false;
            }
        }

        /// <summary>
        /// Stops the server.
        /// </summary>
        public void Stop()
        {
            try
            {
                active = false;
                socket.Close();
            }
            catch { }
        }

        /// <summary>
        /// Method in which the server listens for incoming connections.
        /// </summary>
        private void listen()
        {
            while (active)
            {
                try
                {
                    Socket client = socket.Accept();

                    if (OnClientConnected != null)
                        OnClientConnected(client);

                    Thread thread = new Thread(new ParameterizedThreadStart(work));
                    clientThreads.Add(thread);
                    thread.Start(client);
                }
                catch
                {
                    Stop();
                }
            }
        }

        /// <summary>
        /// Method in which the server communicates with the client.
        /// </summary>
        private void work(object parameter)
        {
            Socket client = (Socket)parameter;

            byte[] buffer = new byte[bufferSize];
            SocketError error = SocketError.Success;

            while (active && client.Connected)
            {
                try
                {
                    int size = client.Receive(buffer, 0, bufferSize, SocketFlags.None, out error);
                    if (error == SocketError.Success && size > 0)
                    {
                        byte[] data = new byte[size];
                        Array.Copy(buffer, data, size);

                        if (OnDataReceived != null)
                            OnDataReceived(client, data);
                    }
                    else
                    {
                        if (OnClientDisconnected != null)
                            OnClientDisconnected(client);

                        client.Shutdown(SocketShutdown.Both);
                        client.Close();
                    }
                }
                catch
                {
                    if (OnClientDisconnected != null)
                        OnClientDisconnected(client);

                    client.Shutdown(SocketShutdown.Both);
                    client.Close();
                }
            }
        }
    }
}
4.506 Beiträge seit 2004
vor 16 Jahren

Hallo idontwantaname,

habe den Code nur eben überflogen, und sage, dass das für Deine aktuellen Zwecke wohl ausreicht (sofern Du getestet hast, ob's auch das tut, was es auf den ersten Blick soll 🙂.

Gruß
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

I
idontwantaname Themenstarter:in
86 Beiträge seit 2006
vor 16 Jahren

Ja, er tut, was er soll ^^

Aber was meinst du, für meine aktuellen Zwecke sollte er reichen?
Ist er fehlerhaft, unperformant oder hast du Verbesserungsvorschläge?

Lg oli

4.506 Beiträge seit 2004
vor 16 Jahren

Hallo idontwantaname,

nein, nein, so ernst ist das nicht 😉

Ich hätte in meiner Lösung wahrscheinlich noch so etwas wie 3x Reconnect Versuch eingebaut, und auch versucht um das Read den oben genannten Timer einzubauen, denn ein TCP/IP Timeout ist standardmäßig auf 1,5 Minuten eingestellt (WinXP).

Aber das sind alles Ergänzungen, keine Verbesserungsvorschläge und für Deinen Anwendungszweck zunächst Oversize. Ich würde Dir empfehlen Dir dann darüber Gedanken zu machen, wenn es soweit ist. Deine Lösung eignet sich gut für solche Anforderungswechsel, und ist meiner Meinung nach deshalb wirklich gut.

Wie gesagt, habe Deinen Code nur überflogen, nicht analysiert und auch nicht ausprobiert 😉

Gruß
Norman-Timo

A: “Wie ist denn das Wetter bei euch?”
B: “Caps Lock.”
A: “Hä?”
B: “Na ja, Shift ohne Ende!”

I
1.739 Beiträge seit 2005
vor 16 Jahren

Ich seh gerad nicht die Lösung des geschilderten Problems.
Der gepostete Code ist irgendwie anders(normal).

I
idontwantaname Themenstarter:in
86 Beiträge seit 2006
vor 16 Jahren

Was meinst du? Ich hab jetzt nicht ganz verstanden, was du zum Ausdruck bringen hast wollen 🤔

I
1.739 Beiträge seit 2005
vor 16 Jahren

Es ist ja auch unwichtig, wenn dein Problem damit gelöst ist. Ich unterstellte wohl einfach ein anderes Problem(das ich so Aufgrund der Beschreibung anfangs so annahm) - Dem scheint nicht so.
Ich seh das so: ist dein Problem gelöst, ist alles ok.
Zweifel bei mir kam nur bei Problemen die ich lösen durfte, und ähnlich erschienen(Anfangsbeschreibung)...

D
1 Beiträge seit 2007
vor 16 Jahren

Hallo, Ich habe die genannte code implementiert und getestet. Es scheint zu functionieren, aber wass Ich sehe ist das Folgende:

Mehrere client habe ein Connection mit den Server gemacht, und data is angekommen.
Wann Ich mit netstat /a untersuchte was mit nicht mehr benutzte connection passiert ware sah Ich das sie nicht 'deleted' werden. Wissen Sie wie Ich das Problem kann losen.

Grusse,

Jan, Niederlande