TCP Socket Timeout
Posted: Sun 7. Mar 2010, 14:10
Hallo,
ich verwende PHP um mich mit dem irserver (Linux) zu verbinden. Dieser bedient dann ein IRTRANS Ethernet.
Hier ein Minimal PHP Skript mit dem das Problem, welches ich im folgenden beschreibe auch auftritt:
Der Aufruf des irservers ist wie folgt:
So sieht die Ausgabe von netstat aus, wenn sowohl irserver als auch das php-Skript gestartet sind:
Nach dem Beenden des PHP Programms sieht es wie folgt aus:
Problem ist nun die Verbindung im Zustand TIME_WAIT. Hier scheint die Verbindung nicht korrekt geschlossen zu sein, obwohl ich ein fclose($fp); durchgeführt habe. Dieser Zustand dauert dann ca. 60 Sekunden. Danach greift scheinbar irgendein Timeout und die Verbindung wird zurückgesetzt.
In der Zeit, in der die Verbindung im Zustand TIME_WAIT ist, ist es beispielsweise nicht möglich den irserver neu zu starten, da der Socket auf Port 21000 belegt bleibt. Woran liegt das?
Ganz konkret habe ich das Problem, dass ich ein Start-Skript habe, welches ich zum restarten des irserver und des PHP-Skripts verwenden möchte. Zunächst beendet das Skript mein PHP-Skript, dann den irserver und dann soll es beide wieder starten, was aber leider aufgrund o.g. Tatsache erst nach ca. 60 Sekunden möglich ist.
Vielleicht kann mir jemand einen Hinweis geben, wo genau das Problem liegt?
Ich selbst habe kürzlich auch einen Server Prozess mit Socket-Anbindung geschrieben und es trat dasselbe Problem auf. Da ich hier selbst den Server beeinflussen konnte, konnte ich das Problem mit einem
beheben. Danach konnte der Port sofort wieder benutzt werden. Wie macht das der irserver genau?
Hier mal das, was ich zu SO_REUSEADDR auf http://docs.hp.com/en/B2355-90136/ch03s01.html gefunden habe:
Hat jemand einen Hinweis, wie ich die Socket Verbindung korrekt beenden kann, so dass dieses Warten auf den Timeout nicht auftritt?
Viele Grüße
André
ich verwende PHP um mich mit dem irserver (Linux) zu verbinden. Dieser bedient dann ein IRTRANS Ethernet.
Hier ein Minimal PHP Skript mit dem das Problem, welches ich im folgenden beschreibe auch auftritt:
- Code: Select all
<?php
$fp = fsockopen("127.0.0.1",21000);
fwrite($fp,"ASCI");
sleep(10);
fclose($fp);
?>
Der Aufruf des irservers ist wie folgt:
- Code: Select all
/usr/local/irtrans irserver -debug_code -timestamp -loglevel 4 192.168.0.40
So sieht die Ausgabe von netstat aus, wenn sowohl irserver als auch das php-Skript gestartet sind:
- Code: Select all
# netstat -an| grep 21000
tcp 0 0 0.0.0.0:21000 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:35260 127.0.0.1:21000 ESTABLISHED
tcp 0 0 127.0.0.1:21000 127.0.0.1:35260 ESTABLISHED
udp 0 0 0.0.0.0:21000 0.0.0.0:*
udp 0 0 192.168.0.10:33427 192.168.0.40:21000 ESTABLISHED
udp 0 0 192.168.0.10:33428 255.255.255.255:21000 ESTABLISHED
Nach dem Beenden des PHP Programms sieht es wie folgt aus:
- Code: Select all
# netstat -an| grep 21000
tcp 0 0 0.0.0.0:21000 0.0.0.0:* LISTEN
tcp 0 0 127.0.0.1:35260 127.0.0.1:21000 TIME_WAIT
udp 0 0 0.0.0.0:21000 0.0.0.0:*
udp 0 0 192.168.0.10:33427 192.168.0.40:21000 ESTABLISHED
udp 0 0 192.168.0.10:33428 255.255.255.255:21000 ESTABLISHED
Problem ist nun die Verbindung im Zustand TIME_WAIT. Hier scheint die Verbindung nicht korrekt geschlossen zu sein, obwohl ich ein fclose($fp); durchgeführt habe. Dieser Zustand dauert dann ca. 60 Sekunden. Danach greift scheinbar irgendein Timeout und die Verbindung wird zurückgesetzt.
In der Zeit, in der die Verbindung im Zustand TIME_WAIT ist, ist es beispielsweise nicht möglich den irserver neu zu starten, da der Socket auf Port 21000 belegt bleibt. Woran liegt das?
Ganz konkret habe ich das Problem, dass ich ein Start-Skript habe, welches ich zum restarten des irserver und des PHP-Skripts verwenden möchte. Zunächst beendet das Skript mein PHP-Skript, dann den irserver und dann soll es beide wieder starten, was aber leider aufgrund o.g. Tatsache erst nach ca. 60 Sekunden möglich ist.
Vielleicht kann mir jemand einen Hinweis geben, wo genau das Problem liegt?
Ich selbst habe kürzlich auch einen Server Prozess mit Socket-Anbindung geschrieben und es trat dasselbe Problem auf. Da ich hier selbst den Server beeinflussen konnte, konnte ich das Problem mit einem
- Code: Select all
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
beheben. Danach konnte der Port sofort wieder benutzt werden. Wie macht das der irserver genau?
Hier mal das, was ich zu SO_REUSEADDR auf http://docs.hp.com/en/B2355-90136/ch03s01.html gefunden habe:
SO_REUSEADDR
This option is AF_INET socket-specific.
SO_REUSEADDR enables you to restart a daemon which was killed or terminated.
This option modifies the rules used by bind to validate local addresses, but it does not violate the uniqueness requirements of an association. SO_REUSEADDR modifies the bind rules only when a wildcard Internet Protocol (IP) address is used in combination with a particular protocol port. The host still checks at connection time to be sure any other sockets with the same local address and local port do not have the same remote address and remote port. Connect fails if the uniqueness requirement is violated.
Example of the SO_REUSEADDR Option
A network daemon server is listening on a specific port: port 2000. If you executed netstat an, part of the output would resemble:
Active connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp 0 0 *.2000 *.* LISTEN
Network Daemon Server Listening at Port 2000
When the network daemon accepts a connection request, the accepted socket will bind to port 2000 and to the address where the daemon is running (e.g. 192.6.250.100). If you executed netstat an, the output would resemble:
Active connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp 0 0 192.6.250.100.2000 192.6.250.101.4000 ESTABLISHED
tcp 0 0 *.2000 *.* LISTEN
New Connection Established, Daemon Server Still Listening
Here the network daemon has established a connection to the client (192.6.250.101.4000) with a new server socket. The original network daemon server continues to listen for more connection requests.
If the listening network daemon process is killed, attempts to restart the daemon fail if SO_REUSEADDR is not set. The restart fails because the daemon attempts to bind to port 2000 and a wildcard IP address (e.g. *.2000). The wildcard address matches the address of the established connection (192.6.250.100), so the bind aborts to avoid duplicate socket naming.
When SO_REUSEADDR is set, bind ignores the wildcard match, so the network daemon can be restarted. An example usage of this option is:
int optval = 1;
setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &optval,
sizeof(optval));
bind (s, &sin, sizeof(sin));
Hat jemand einen Hinweis, wie ich die Socket Verbindung korrekt beenden kann, so dass dieses Warten auf den Timeout nicht auftritt?
Viele Grüße
André