Laden...

TcpClient BeginConnect wirft Fehler

Erstellt von Lost-Ha(n)f-PHP vor 14 Jahren Letzter Beitrag vor 14 Jahren 3.012 Views
Lost-Ha(n)f-PHP Themenstarter:in
58 Beiträge seit 2007
vor 14 Jahren
TcpClient BeginConnect wirft Fehler

Hallo miteinander,

ich benutze in meinem Programm einen TcpClient und darin die Methode BeginConnect, um einmal eine Verbidung zu diesem Server aufzubauen (logisch) und andererseits um festzustellen, ob der Server überhaupt a) verfügbar ist und b) auf diesem Port lauscht.
Desweiteren gibt mir das die Möglichkeit einen Timeout zu setzen. Aber genau an der Stelle hakt es gerade. Mein Code ist folgender:


public bool Connect(string Host, int Port) {
	try {
		_cln = new TcpClient();
		IPAddress[] ips = Dns.GetHostAddresses(Host);
		if(!_cln.BeginConnect(ips[0], Port, Connecting, null).AsyncWaitHandle.WaitOne(3000, true)) {
		// [...]
		}
	// [...]
	} catch {
		// [...]
	}
}

private void Connecting(IAsyncResult ar) {
	// Aufruf nach 30 Sekunden
	if(ar.IsCompleted) {
		_cln.EndConnect(ar);
	}
}

Der Timeout funkioniert auch wie vorgesehen, aber nach ca. 30 Sekunden ruft das Programm dann doch Connecting auf. ar.IsCompleted ist dann true und das Programm versucht einen EndConnect, was in einer Exception endet. Es ist ja auch nicht das Problem die Exception abzufangen, sondern die lange zeit, die das Programm braucht, bis es dahin kommt. Sollte ich in dieser Zeit versuchen einen neuen TcpClient zu erstellen (_cln = new TcpClient(...)), dann endet der Verbindungsaufbau ebenfalls in einer Exception, wenn diese 30 Sekunden noch nicht abgelaufen sind.

Kann man da irgend etwas machen? Vielleicht, dass Connecting gar nicht mehr aufgerufen wird, wenn WaitOne() == false ist?

Mit freundlichem Gruß

Lost-Ha[n]f-PHP

M
90 Beiträge seit 2009
vor 14 Jahren

Hallo Lost-Ha(n)f-PHP,

Der Timeout funkioniert auch wie vorgesehen, aber nach ca. 30 Sekunden ruft das Programm dann doch Connecting auf. ar.IsCompleted ist dann true und das Programm versucht einen EndConnect, was in einer Exception endet.

Hier muss es nicht zu einer Exception kommen. IAsyncResult.IsCompleted gibt nur darüber Aufschluss, ob der asynchrone Vorgang abgeschlossen ist, nicht ob die Verbindung erfolgreich war. Folglich sollte hier kein EndConnect aufgerufen werden.


Du wirst auf diese Weise nicht verhindern können, dass Connecting aufgerufen wird, immerhin sagst du ja, dass es so geschehen soll und das ist beim asynchronen Prozess auch wünschenswert.

Ich weiß leider nicht ganz genau, was du bezweckst. Aber WaitOne wartet nur eine beliebige Zeit auf den Thread, nicht darauf, dass der asynchrone Prozess abgeschlossen wird. Das zugrunde liegende Timeout für die TCP Connect Vorgang lässt sich meines Wissens nicht beeinflussen.

Wenn du jetzt also nochmals Connect(string Host, int Port) aufrufst, während der andere Vorgang noch läuft, kann es durchaus zu einem Mischmasch kommen, du verwendest innerhalb von Connecting immerhin jeweils die gleiche Membervariable.

Mein Lösungvorschlag:



        public bool Connect(string Host, int Port)
        {
            try
            {
                TcpClient newConnection = new TcpClient();
                IPAddress[] ips = Dns.GetHostAddresses(Host);
                if (!newConnection.BeginConnect(ips[0], Port, Connecting, newConnection).AsyncWaitHandle.WaitOne(3000, true))
                {
                    // [...]
                }
                // [...]
            }
            catch
            {
                // [...]
            }
        }



        public void Connecting(IAsyncResult result)
        {
            if (result.IsCompleted)
            {
                TcpClient client = result.AsyncState as TcpClient;
                if (client != null)
                {
                    if (client.Connected)
                    {
                        client.Close();
                    }
                }
            }
        }



Du übergibst also die TcpClient Instanz als State-Object und lässt sie bei Bedarf dann einfach automatisch am echten Prozessende wieder schließen.
Was du jetzt genau in deinem Fall weiter machen willst, müssest du allerdings noch genauer erklären.

EDIT:
Mir ist noch eingefallen, mein Ansatz ist jetzt aber insofern gefährlich, da jetzt eine jede erfolgreiche Verbindung gleich wieder beendet wird. Von daher kannst du mit newConnection nach deinem IF nicht weiterarbeiten. Man müsste hier natürlich dann das Konzept verfeinern, je nachdem, was du machen willst. Ich weiß ja leider nicht, was für ein "Warteschema" dein restliches Programm hat.

Gruß Joe