socket / fork() problem
-
Hi,
ich habe auf einer RedHat Linux 7.3 Kiste einen
Daemon laufen, welcher auf einen bestimmten Port lauscht und
auf Client anfragen (natürlich auf mehrere(via fork)) wartet.
Der Daemon startet im Hintergrund wieder via fork().
Somit lauscht der Daemon im Hintergrund und nimmt auch Client Anfragen
entgegen.
Sende ich nun Daten vom Client an den Server, wird nach einer
definierten endekennung die Connection geschlossen(scheinbar),
zumindest Verliert der Client die Verbindung.
Doch Serverseitig besteht die Verbindung weiterhin.
D.H.: kille ich den Daemon, via SIGTERM, bleibt die Verbindung
weiterhin bestehen, trotz schliessen des Sockets!
Somit kann der Daemon beim neustart denn Port nicht mehr binden, erst
nach einer weile, steht er wieder zur Verfügung!
eine sehr nervige Angelegenheit, da ich immer warten muss, bis der
Socket von selbst schliesst!Hier mein Quellcode:
//------------------------------------------------- void term(int sig) //SIGTERM Handler { cout <<"raus"; close(curSock); close(sock); exit(1); } int main(int argc, char **argv) { #define buflen 1024 int curlen = buflen; char inbuf[buflen+1]; char ende[]="!"; //Endekennung int status; int status_main; int port = 3737; //Port struct sockaddr_in adr; struct sockaddr_in clientName; struct protoent *proto = getprotobyname("tcp"); int protocol = (*proto).p_proto; if ((sock = socket(PF_INET, SOCK_STREAM, protocol)) == -1) { //Socket erstellen printf("Error creating socket."); return 1; } adr.sin_family = AF_INET; adr.sin_port = htons(port); adr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(sock, (struct sockaddr*)&adr, sizeof(adr)) == -1) { //Socket an Port binden //while (bind(sock, (struct sockaddr*)&adr, sizeof(adr)) == -1){ //Wenn belegt, versuche erneut //sleep(1); //} printf("Error bind on socket."); return 1; } if(listen(sock, 2)) { //Nun lausche auf Port printf("Error listening on socket.\n"); return 1; } status_main = fork(); //Haupt-fork Programm läuft im Hintergrund if(status_main == -1) { fprintf(stderr, "fork failed.\n"); } if(status_main>0) { //Vaterprozess close(sock); exit(0); } else { //Child Prozess } setsid(); //Prozessgruppenführer signal(SIGTERM, term); //Wenn Sigterm --> term() while(1) { //Endlosschleife unsigned int clientLength = sizeof(clientName); curSock = accept(sock, (struct sockaddr*) &clientName,&clientLength); if(curSock == -1) { //Socket nicht akzeptiert printf("Error accept().\n"); return -1; } status = fork(); //Fork--> Handling für mehrere Client Anfragen if(status == -1) { fprintf(stderr, "fork failed.\n"); } if(status>0) { //Vaterprozess close(curSock); exit(0); } else { //Childprozess für jede Client Anfrage while((curlen = read(curSock, inbuf, buflen)) > 0 ) { //Lese vom Client inbuf[curlen] = 0; if (!strcmp(inbuf,ende)){ //Wenn Endekennung erreicht cout <<"Verbindung wird getrennt!"; close(curSock); //Conection schliessen exit(0); } } //return 0; } } //Ende Endlosschleife } //Ende Main //-------------------------------------------------
Ich hoffe, Ihr könnt mir weiterhelfen!
Vielen Dank
mfg Christof
-
hab keine Zeit groß nachzuforschen, aber guck dir mal setsockopt(2) / socket(7) => SO_REUSEADDR an
-
naja, eine kleine Code Kritik von mir
cout <<"raus"; //... printf("Error creating socket.");
iostream und stdio funktionen zu mischen ist nicht gut, wenn man nicht ostream::sync_with_stdio() aufruft (aber man sollte generell C++ und C Mischungen vermeiden). Außerdem würde ich perror benutzen, bei einem Fehler, da die Fehlermerlund dann mit ausgegeben wird
#define buflen 1024[/url] #define ist schlecht! mach lieber const size_t buflen=1024; [code type="c++"]char ende[]="!";
dafür reicht doch auch ein char ende='!'; dann sparst du auch das teure strcmp
int protocol = (*proto).p_proto;
dafür haben wird doch den schönen -> Operator
int protocol=proto->p_proto;
if(status_main == -1) { //... if(status_main>0) { //... else {
dafür bietet sich doch switch an, was bei einigen Compilern schneller ist als if.
Außerdem sollte man Daemonen 2 mal forken! Schau dir am besten mal den Code hier an wie bekomm ich mein prog dazu das es als daemon läuft
-
Hi,
Somit kann der Daemon beim neustart denn Port nicht mehr binden, erst
nach einer weile, steht er wieder zur Verfügung!Ist voellig normal, da es sein kann, dass vom Verbindungspartner noch
Packete ankommen, die nur laenger gebraucht haben. Soweit ich weiss,
bleibt der Port 'gebinded' (was fuer ein schoenes Wort ;)), bis die
doppelte Zeit, die ein Packet im Internet ueberleben kann ohne das es
sein Ziel erreicht, verstrichen ist. Das kann einige minuten dauern.Loesungen dazu, wurden ja schon genannten.
mfg
v R
-
@Bashar :
Klasse!!!
Was mann mit nem zweizeiler(naja 1 1/2) alles erreicht! Hat wunderbar geklappt!!
Vors bind einfach:int on = 1; setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
Vielen Dank!!!
@kingruedi:
Danke für die hilfreichen Tips!!
momentan kann mann ja noch nicht von umbedingt sauberen Code reden,
das iss mir bewusst!
Werde da noch ein bissl aufräumen müssen!
Werden mir dabei deine Anregungen zu gemüte führen!
Der Sinn des 2mal forken ist mir allerdings noch nicht so bewusst!
Vielen Dank!!!gruss Christof
-
zum Thema 2. fork
http://www.faqs.org/faqs/unix-faq/programmer/faq/ 1.7
3. `fork()' again so the parent, (the session group leader), can exit.
This means that we, as a non-session group leader, can never regain a
controlling terminal.