Problem beim Portieren einer Socketklasse:Server funktioniert nicht(kann das Problem nicht näher bestimmen)



  • Hi,
    also ich hab jetzt mit zig #defines endlich meine Socket Klasse unter Linux zum laufen gebracht!
    Nun ja den Client-Teil 🙂
    Und beim Serverteil passiert folgendes(der Client funzt übrigens 100%ig):

    linux:/home/coding/sockets # ./server
    Initalizing...Done!
    [WARTEN BIS:CLIENT CONNECTED]
    Waiting for client...Client connected!
    Receiving...
    WARTEN BIS:NEUER CLIENT CONNECTED]
    Waiting for client...Client connected!
    Receiving...

    Richtig wäre:

    Initalizing...Done!

    Waiting for client...[WARTEN BIS:CLIENT CONNECTED]Client connected!
    Receiving...
    [WARTEN BIS:CLIENT DATEN SENDET]
    Done:

    Hallo?Wie gehts?

    Receiving...
    [WARTEN BIS:CLIENT DATEN SENDET]

    Der Code dazu:

    #include <string>
    #include <iostream>
    #include "sockets.h"
    using namespace std;
    
    int main(void)
    {
    string get;
    
    cout << "Initalizing...";
    NetSocket sx;
    cout << "Done!\n";
    
    cout << "Waiting for client...";
    sx.server_open(8080);
    cout << "Client connected!\n";
    
    while(1)
    {
    
    cout << "Receiving...\n";
    get = sx.receive_message();  /* <== */
    
    if (sx.error_b == 2) //Client hat verbindung abgebrochen
     sx.server_open(8080);
    else if (sx.error_b == 1)
     cout << "Error:\n" << sx.error << endl;
    else
     cout << "Done:\n\n" << get << endl;
    
    }
    
    return 0;
    }
    
    cout << "Initalizing...";
    NetSocket sx;
    cout << "Done!\n";
    

    führt er also aus,

    cout << "Initalizing...";
    

    aber nicht!
    Stattdessen wartet er bis ein Client connected und führt

    cout << "Waiting for client...";
    cout << "Client connected!\n";
    

    aus!
    Das ist imo wirklich SEHR komisch,unter Windows funzt alles!
    Hier die 2 Funktionen der Klasse:

    string NetSocket::receive_message(int lenght = 0)    
    {
    error_b = 0;
    string received;
    timeval t;
    t.tv_sec  = 0;
    t.tv_usec = 0;
    
    char buf[MAX_LENGHT];
    
     do{
      rc = recv(s,buf,lenght,0);
      if(rc==0 || rc==SOCKET_ERROR)
       {
        error_b = 2;
        break;  
       }
    
        buf[rc]='\0';
        received += buf;
    
        FD_ZERO(&fdSet); 
        FD_SET(s,&fdSet); 
        rc2=select(0,&fdSet,NULL,NULL,&t); 
    
    }while(FD_ISSET(s,&fdSet) );    //&& rc != SOCKET_ERROR 
    
    return received;    
    }
    
    void NetSocket::server_open(int port)
    {
     if(s)
      closesocket(s);
     if(s1)
      closesocket(s1);
    
     s1=socket(AF_INET,SOCK_STREAM,0);
      if(s1==INVALID_SOCKET)
      {
        error_b = 1 ;
        error += "Could not create Socket!\n";
        return ;
      }
    
      memset(&addr,0,sizeof(SOCKADDR_IN));
      addr.sin_family=AF_INET;
      addr.sin_port=htons(port);
      addr.sin_addr.s_addr=ADDR_ANY;
      rc=bind(s1,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));
    
      if(rc==SOCKET_ERROR)
      {
        error_b = 1 ;
        error += "Could not bind socket!\n";
      } 
    
      rc=listen(s1,10);
    
      if(rc==SOCKET_ERROR)
      {
        error_b = 1 ;
        error += "Server is not listening!\n";
      }
    
    #ifdef _WIN32_WINNT
    s=accept(s1,NULL,NULL);
     if(s==INVALID_SOCKET)
      {
        error_b = 1 ;
        error += "Server could not accept connection!\n";
      }
    #else
    struct sockaddr_in client;
    socklen_t len;
    len = sizeof( client );
    s = accept(s1,(struct sockaddr*)&client, &len);
    
     if (s < 0) 
      {
       error_b = 1 ;
       error += "Server could not accept connection!\n";
      }
    #endif
    
    }
    

    Hab ich hier alles richtig durch #ifdefs nach Linux portiert?
    Der Client funzt ja 1A 🙂

    Schon mal vielen Dank im voraus!



  • Verdammt ich kann hier nicht editieren 😞 Sorry für doppelpost aber so ist die Funktion richtig:

    string NetSocket::receive_message(int lenght = 0)    
    {
    error_b = 0;
    string received;
    timeval t;
    t.tv_sec  = 0;
    t.tv_usec = 0;
    
    char buf[MAX_LENGHT];
    
     do{
      rc = recv(s,buf,MAX_LENGHT,0);
      if(rc==0 || rc==SOCKET_ERROR)
       {
        error_b = 2;
        break;  
       }
    
        buf[rc]='\0';
        received += buf;
    
        FD_ZERO(&fdSet);
        FD_SET(s,&fdSet);
        rc2=select(0,&fdSet,NULL,NULL,&t);
    
    }while(FD_ISSET(s,&fdSet) );    //&& rc != SOCKET_ERROR
    
    return received;    
    }
    

    Hab einmal length mit MAX_LENGHT ersetzt ^^



  • mir sieht der select() - Aufruf komisch aus:

    rc2=select(0,&fdSet,NULL,NULL,&t);
    

    Ich habe den Aufruf mal mit meinem üblichen Aufrufschema verglichen.
    Ich benutze zwar immer ein timeout, Du hast die timval-Struktur mit 0 sec/msec belegt, d.h. der Aufruf kommt sofort wieder zurück, ist aber auch kein Problem und wahrscheinlich auch beabsichtigt.

    Allerdings kommt mir der erste Parameter komisch vor. Hier sollte lt. Manual ("n is the highest-numbered descriptor in any of the three sets, plus 1.")
    der Wert des höchsten Filedescriptors + 1 stehen. 0 scheint mir hier nicht angemessen. FD_ISSET(s,&fdSet) müßte folglich immer 0 ergeben. Ich tippe mal in Deinem Fall auf s+1 für den korrekten Wert des 1. Parameters.

    ... den Rest habe ich noch nicht weiter angesehen. Überprüf erst einmal diesen Parameter.



  • ... und noch einen Nachtrag:

    ich würde bei

    rc = recv(s,buf,MAX_LENGHT,0);
    

    als maximale Länge MAX_LENGTH-1 angeben, wenn Du hinten (maximal an der letzten Position) noch 0x00 ranhängen willst.

    ... und eine weitere Idee:

    Bei mir sieht der Ablauf bei Benutzung eines select() anders aus, ganz grob so:

    while (1)
        {
        FD_ZERO(..);
        FD_SET(..);
        rc = select(...) /* wartend mit timeout */
        if (rc < 0)
            ...Fehler...
        else if (rc == 0)
            ...timeout...
            break;
        else if (FD_SET(...))
            ...lesen von socket/filedescriptor...
        }
    

    Wenn ich den Ablauf in Deinem Programm richtig interpretiere, machst Du ein blockierendes Lesen mittels recv() und prüfst dann, ob noch was auf dem Kanal da ist. Was ist aber, wenn vom dem kompletten Socket-Puffer alles in Deinen Puffer eingelesen wurde, d.h. alle Input-Bytes verbraucht sind, und bis zu Deinem select() - Aufruf keine neuen Daten vom Client angekommen sind?

    ... ach so, typisch ist bei Unix/Linux auch noch, dass der select() sporadisch auch noch unterbrochen wird und dann mit -1 und errno==EINTR zurückkommt (was dann keinen Fehler darstellt). Auf anderen Unix-Dirivaten, z.B. Solaris sind dann auch noch weitere Interrupts möglich/erlaubt.


Anmelden zum Antworten