Willkommen ~Gast!
Registrieren || Einloggen || Hilfe/FAQ || Staff
Probleme mit der Registrierung im Forum? Melde dich unter registerEin Bild.
Autor Beitrag
000
12.04.2007, 17:46
Felheart



Hi,
ich bin heute einem recht ungewöhnlichen Problem begenet als ich mit
TCP Sockets rumexperimentiert habe.

Also ich habe einen Server und einen Clienten.
Wenn ich beide anmache und die beiden sich "verbinden"
läuft alles gut, der client schickt dem server munter seine rand(); zahlen.

Wenn ich jetzt aber einen verbindungsabbruch simmuliere indem ich einfach den
Server beende, geht die CPU auslastung des Clients auf einmal auf 100%.
Andersherum wenn ich den Client beende spinnt der Server...

Ich muss beide Programme neustarten das alles wieder normal geht.
Wie kann ich das verhindern ?

Ich hab schon überall printf's und Sleep's eingebaut um zu sehen ob und wo
ich vieleicht ein eine for(;;) Schelife rattern könnte.

Aber alles ohne erfolg!

--

zum Seitenanfang zum Seitenende Profil || Suche
001
12.04.2007, 20:51
Cpt. Rick



Ich weiß nicht genau wo dein Error liegt (ein bischen code wäre vllt ganz hilfreich).
Aber das könnte vllt helfen http://www.c-worker.ch/tuts/wstut_op.php
Es ist zwar C, aber hier wird ua erklärt wie man error abfängt.

--

zum Seitenanfang zum Seitenende Profil || Suche
002
15.04.2007, 17:57
Felheart



Ok, hier ein DL link zu den Sources:
http://filebeam.com/4e67c8a378780e7b64ecc5eb3d5f2cd1

Inzwischen ist zwar ein chat programm daraus geworden aber das problem
ist das geliche geblieben.

ausserdem ist jetzt noch dazugekommen das der client die ganze zeit
Die letzte nachricht in der Console spammt wenn die verbindung weg ist
>_<

--

zum Seitenanfang zum Seitenende Profil || Suche
003
15.04.2007, 20:26
feigling



Das Problem kenne ich. Das liegt dadran, dass select() fehlschlägt, weil die Verbindung abgebrochen ist und damit die CPU zu 100% belastet wird, weil eben die Hauptschleife immer durchläuft und select() nicht mehr "blockiert" bzw die angegebene Zeit wartet. So ganz habe ich auch noch nicht rausgefunden, wie man das fixen kann. Mein Code sieht im Moment so aus (weiter unten), aber ich bin mir nicht wirklich sicher, ob ich das damals gefixt hatte oder nicht. So wie mein Code aussieht, würde ich eher vermuten, dass es nicht gefixt ist, aber ka.

Quellcode:void
socket_loop(void)
{
    struct timeval tval;
    fd_set read_flag;

    tval.tv_sec = 1;
    tval.tv_usec = 0;

    FD_ZERO(&read_flag);
    FD_SET(bot_info.socket, &read_flag);

    if(select(bot_info.socket + 1, &read_flag, NULL, NULL, &tval) < 0)
        return;

    if(FD_ISSET(bot_info.socket, &read_flag))
    {
        FD_CLR(bot_info.socket, &read_flag);
        socket_receive();
    }
}
Das sinnvollste wird wohl einfach sein, dass wenn select() < 0 zurückliefert, man einfach den Socket closed und aus der Hauptschleife springt, also bei mir anstatt "return;" dann irgendwie "exit_loop = 1;".

--


Dieser Beitrag wurde am 15.04.2007 um 20:28 von feigling bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
004
16.04.2007, 14:16
Felheart



select() ?

ich hab zwar schon sehr oft von dieser funktion gehört / gelesen,
aber ich benutz sich überhaupt nicht in meinem projekt oO

Wenn du dir den beigelegeten code anschaust siehst du das ich
das problem mit den mehreren clients einfach mit threads gelöst habe.

Ist es den ratsamer mit select seine clients auszuwählen ?
immerhin giebts es ja bei mir immer nur soviele threads wie auch clients verbunden sind.
und clients die nichts senden beanspruchen die threads im server ja auch nicht.

Btw: dabei noch ne frage zu recv():

wenn ein socket etwas via recv empfängt und die das dann "lange" bearbeitet
(z.B. nach dem recv() ein Sleep(3000); )

und wenn der client ind diesen 3 sekunden nochmals etwas sendet,
wartet das empfangene einfach bis es per recv() vom socket oder so
ins programm geholt wird ?
oder giebts dann da irgenwo nen fehler ?

--

zum Seitenanfang zum Seitenende Profil || Suche
005
16.04.2007, 15:47
HammerBlade



Quellcode:do
        {
            int ERR;
            ERR = recv(s, (char*)&temp,sizeof(temp),0);

            if (ERR == -1 || ERR == WSAECONNRESET || ERR == WSAECONNABORTED)
            {
                printf("Connection Terminated\n");
            }

            recived += ERR;
        } while(recived < sizeof(temp));
Du solltest da die while-Schleife abbrechen, wenn beim recv() ein Fehler auftritt und nicht noch den Errorcode auf den Zähler addieren, denn der zählt dann möglicherweise runter statt rauf und deine Scheilfe bricht lange nicht ab (bis der int overflowed).

Bist du sicher das recv() WSA Errorcodes zurückgibt? Ich denke WSARecv() wird das hächstens tun. recv() wird seine Errorcodes in errno ablegen (da bin ich aber gerade unsicher drüber).

Zitat:
Felheart postete
Ist es den ratsamer mit select seine clients auszuwählen ?
immerhin giebts es ja bei mir immer nur soviele threads wie auch clients verbunden sind.
und clients die nichts senden beanspruchen die threads im server ja auch nicht.
Bis du sicher, dass der Zugriff von printf auf stdout threadsafe ist? Wenn das nicht der Fall ist (was ich annehme, aber nicht sicher weiss) kann es passieren, dass Client A "aaaaaa" sendet und Client B "bbbbbb" sendet, das dann aber auf der Console nicht als "aaaaaa\nbbbbbb\n", sondern als "aaabbbaaa\nbbb\n" ankommt. Je nachdem wie die Thread gerade gescheduled werden. Soll heissen du solltest das vielleicht mit einem Mutex (bzw. auf Windows einer CriticalSection) schützen.

Zitat:
Felheart postete
Btw: dabei noch ne frage zu recv():

wenn ein socket etwas via recv empfängt und die das dann "lange" bearbeitet
(z.B. nach dem recv() ein Sleep(3000); )

und wenn der client ind diesen 3 sekunden nochmals etwas sendet,
wartet das empfangene einfach bis es per recv() vom socket oder so
ins programm geholt wird ?
oder giebts dann da irgenwo nen fehler ?

Sockets haben Eingangs- und Ausgangsbuffer einer bestimmten Grösse, welche Schwankungen auffangen können, d.h. bei dem geringen Datenaufkommen eines Chats wirst du auch mit 3sec Bearbeitungszeit keine Probleme haben.

--

"Mit C++ (noch besser mit C) kann man sich _sehr_ leicht in den Fuss schiessen." - theDon
Auspack und freu! - Auszug aus einer, aus dem japanischen übersetzten, Bedienugsanleitung für ein Spielzeugaquarium.
--
Photon Audio Player | Majestic42.net | How To Ask Questions The Smart Way


Dieser Beitrag wurde am 16.04.2007 um 15:48 von HammerBlade bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
006
16.04.2007, 17:06
Felheart



Zitat:
Bist du sicher das recv() WSA Errorcodes zurückgibt? Ich denke WSARecv() wird das hächstens tun. recv() wird seine Errorcodes in errno ablegen (da bin ich aber gerade unsicher drüber).
Ok, stimmt.
" || ERR == WSAECONNRESET || ERR == WSAECONNABORTED" == quatsch :D

Zitat:
Bis du sicher, dass der Zugriff von printf auf stdout threadsafe ist? Wenn das nicht der Fall ist (was ich annehme, aber nicht sicher weiss) kann es passieren, dass Client A "aaaaaa" sendet und Client B "bbbbbb" sendet, das dann aber auf der Console nicht als "aaaaaa\nbbbbbb\n", sondern als "aaabbbaaa\nbbb\n" ankommt. Je nachdem wie die Thread gerade gescheduled werden. Soll heissen du solltest das vielleicht mit einem Mutex (bzw. auf Windows einer CriticalSection) schützen.
Werd mich informieren, das wird aufjedenfall gemacht
(Und ja das mit dem aabaabbb ist schon passiert.)

Zitat:
Sockets haben Eingangs- und Ausgangsbuffer einer bestimmten Grösse, welche Schwankungen auffangen können, d.h. bei dem geringen Datenaufkommen eines Chats wirst du auch mit 3sec Bearbeitungszeit keine Probleme haben.
Aso, thx

--


Dieser Beitrag wurde am 16.04.2007 um 17:07 von Felheart bearbeitet.
zum Seitenanfang zum Seitenende Profil || Suche
007
16.04.2007, 19:10
feigling



Ja, select ist besser als Threads oder du kannst auch epoll benutzen (#include <sys/epoll.h>) falls das dein Server unterstützt. Übrigens sind Variablennamen in Großbuchstaben böse. Nur defines sollten vollständig caps sein. Und received schreibt man mit nem "e" und ned recived += ERR; ;x

--

zum Seitenanfang zum Seitenende Profil || Suche