[c++/winAPI]Socket -select()

kickerxy123

Erfahrenes Mitglied
Hallo!
Ich habe folgenden Server kompilieren können und er arbeitet auch wunderbar:
Code:
#include <windows.h>
#include <stdio.h>
#define MAX_CLIENTS 10
using namespace std;

int startWinsock(void)
{
  WSADATA wsa;
  return WSAStartup(MAKEWORD(2,0),&wsa);
}

int main()
{
  long rc;
  SOCKET acceptSocket;
  SOCKADDR_IN addr;
  char buf[256];
  char buf2[300];
  FD_SET fdSet;
  SOCKET clients[MAX_CLIENTS];

  rc=startWinsock();
  if(rc!=0)
  {
    printf("Fehler: startWinsock, fehler code: %d\n",rc);
    return 1;
  }
  else
  {
    printf("Winsock gestartet!\n");
  }

  acceptSocket=socket(AF_INET,SOCK_STREAM,0);
  if(acceptSocket==INVALID_SOCKET)
  {
    printf("Fehler: Der Socket konnte nicht erstellt werden, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
  {
    printf("Socket erstellt!\n");
  }

  memset(&addr,0,sizeof(SOCKADDR_IN));
  addr.sin_family=AF_INET;
  addr.sin_port=htons(12345);
  addr.sin_addr.s_addr=INADDR_ANY; 
  rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));
  if(rc==SOCKET_ERROR)
  {
    printf("Fehler: bind, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
  {
    printf("Socket an port 12345 gebunden\n");
  }

  rc=listen(acceptSocket,10);
  if(rc==SOCKET_ERROR)
  {
    printf("Fehler: listen, fehler code: %d\n",WSAGetLastError());
    return 1;
  }
  else
  {
    printf("acceptSocket ist im listen Modus....\n");
  }
for(unsigned short i=0;i<MAX_CLIENTS;i++) 
  {
    clients[i]=INVALID_SOCKET;
  }
while(1) 
  {

FD_ZERO(&fdSet); // Inhalt leeren
    FD_SET(acceptSocket,&fdSet); // Den Socket der verbindungen annimmt hinzufügen
    
    // alle gültigen(!=INVALID_SOCKET) client sockets hinzufügen 
    for(unsigned short i=0;i<MAX_CLIENTS;i++) 
    {
      if(clients[i]!=INVALID_SOCKET)
      {
        FD_SET(clients[i],&fdSet);
      }
    }

rc=select(0,&fdSet,NULL,NULL,NULL); 
    if(rc==SOCKET_ERROR) 
    {
      printf("Fehler: select, fehler code: %s\n",WSAGetLastError());
      return 1;
    }
       //wenn acceptSocket im fd_set(und platz) => verbindung annehmen
    if(FD_ISSET(acceptSocket,&fdSet)) {
      // einen freien platz für den neuen client suchen, und die verbingung annehmen
      for(unsigned short i=0;i<MAX_CLIENTS;i++)
      {
        if(clients[i]==INVALID_SOCKET) 
        {
          clients[i]=accept(acceptSocket,NULL,NULL);
          printf("Neuen Client angenommen (%d)\n",i);
          break;
        }
      }
    }


    // prüfen welche client sockets im fd_set sind
    for(unsigned short i=0;i<MAX_CLIENTS;i++) 
    {
      if(clients[i]==INVALID_SOCKET)
      {
        continue; // ungültiger socket=>i++
      }
      if(FD_ISSET(clients[i],&fdSet))
      {
        rc=recv(clients[i],buf,256,0);
        // prüfen ob die verbindung geschlossen wurde oder ein fehler auftrat
        if(rc==0 || rc==SOCKET_ERROR)
        {
          printf("Client %d hat die Verbindung geschlossen\n",i);
          closesocket(clients[i]);        
          clients[i]=INVALID_SOCKET; // seinen platz wieder freigeben für andere
        } 
        else
        {
          buf[rc]='\0';
          // daten ausgeben und eine antwort senden
          printf("Client %d hat folgendes gesandt: %s\n",i,buf);
          // antwort senden
          sprintf(buf2,"Du mich auch %s\n",buf);
          send(clients[i],buf2,(int)strlen(buf2),0);
        }
      }
    }
  }
}
Jetzt wollte ich das ganze in winAPI verpacken, naja.. klappt eigentlich auch, nur, dass er sich jetzt bei acceptSocket aufhängt und nciht mehr reagiert!
Hier ein CODEAuszug:
Code:
         if(lParam == (LPARAM)hStart)
         {
             if(HIWORD(wParam) == BN_CLICKED)
         
EnableWindow(hStart,false);
EnableWindow(hEdit2,false);
EnableWindow(hStandard,false);
EnableWindow(hStop,true);
GetWindowText(hEdit2, lpString2, GetWindowTextLength(hEdit2)+1);
GetWindowText(hEdit3, lpString3, GetWindowTextLength(hEdit3)+1);         
            ofstream mo ("C:/Programme/server.txt",ios::trunc);
            mo << lpString2 << endl << lpString3;
            mo.close();
            delete lpString2; delete lpString3;

                           GetWindowText(hFortschritt, lpString_Fortschritt, GetWindowTextLength(hFortschritt)+1);
                           string bla ="Server wurde erfolgreich gestartet.";
                           str_fortschritt ="";
                           str_fortschritt+= lpString_Fortschritt;
                           str_fortschritt+="\r\n";
                           str_fortschritt+=bla;
                               
                           SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str());    

rc=startWinsock();
 if(rc!=0)
  {
            str_fortschritt+="\r\n";
            str_fortschritt+="Fehler: StartWinsock, Fehler Code:";
            str_fortschritt+=rc;
            SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str());
            return 1;
  }
  else
  {    str_fortschritt+="\r\n";
       str_fortschritt+="Winsock gestartet!";
       SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str());    
  }  
 // Socket erstellen
  acceptSocket=socket(AF_INET,SOCK_STREAM,0);

  if(acceptSocket==INVALID_SOCKET)
  {
            str_fortschritt+="\r\n";
            str_fortschritt+="Fehler: Der Socket konnte nicht erstellt werden, fehler code: ";
            str_fortschritt+=WSAGetLastError();
            SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str());
            return 1;
  }
  else
  {
       str_fortschritt+="\r\n";
       str_fortschritt+="Socket erstellt!";
       SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str()); 
  } 
  
memset(&addr,0,sizeof(SOCKADDR_IN));
addr.sin_family=AF_INET;

addr.sin_port=htons(port);//Standard: 2001
addr.sin_addr.s_addr=ADDR_ANY;
rc=bind(acceptSocket,(SOCKADDR*)&addr,sizeof(SOCKADDR_IN));

if(rc==SOCKET_ERROR)

{
            str_fortschritt+="\r\n";
            str_fortschritt+="Fehler: Socketbinding, fehler code: ";
            str_fortschritt+=WSAGetLastError();
            SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str());
            return 1;

}

else

{
       str_fortschritt+="\r\n";
       str_fortschritt+="Socket an Port ";
       string g;
ifstream mo ("C:/Programme/server.txt");
getline(mo,g,'\n');
mo.close();
       str_fortschritt+=g;
       str_fortschritt+=" gebunden";
       SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str()); 


}   
SendMessage(hwnd,WM_SIZE,0,0);  //UpdateWindow


rc=listen(acceptSocket,10);

if(rc==SOCKET_ERROR)

{
            str_fortschritt+="\r\n";
            str_fortschritt+="Fehler: Listen Socket, fehler code: ";
            str_fortschritt+=WSAGetLastError();
            SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str());
            return 1;
}

else

{
       str_fortschritt+="\r\n";
       str_fortschritt+="acceptSocket ist im listen Modus.....";
       SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str());
       SendMessage(hwnd,WM_SIZE,0,0); 
}  
  for(unsigned short i=0;i<MAX_CLIENTS;i++) 
  {
    clients[i]=INVALID_SOCKET;
  }
 while(1){  
 FD_ZERO(&fdset); //Inhalt leeren
 FD_SET(acceptSocket, &fdset);  //Den Socket der Verbindungen annimt hinzufügen

 //Alle gültigen(!=INVALID_SOCKET)client sockets hinzufügen:
        for(unsigned short i=0;i<MAX_CLIENTS;i++)
        {
                     if(clients[i]!=INVALID_SOCKET)
                         {
                            FD_SET(clients[i],&fdset);
                         }
        }
rc = select(0,&fdset,NULL,NULL,NULL);
if(rc==SOCKET_ERROR)
{
 
       str_fortschritt+="\r\n";
       str_fortschritt+="select-Fehler, Code:";
       int vy = WSAGetLastError();
       char pq[256];                                 //int ->char Konvertierung!
       sprintf(pq, "%d",vy);
        str_fortschritt +=pq;
       SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str());
       return 1;
}
//wenn accepsocket im fd_set ist und genügend platz => verbindung annehmen
if(FD_ISSET(acceptSocket,&fdset))
{
  //freien Platz suchen
  for(unsigned short i = 0; i< MAX_CLIENTS;i++)
  {
               if(clients[i]==INVALID_SOCKET)
               {
                        clients[i]=accept(acceptSocket,NULL,NULL);
                         str_fortschritt+="\r\n";
                         str_fortschritt+="Neuen Client ";
                         str_fortschritt+=i;
                         str_fortschritt+=" angenommen.";
                         str_fortschritt+=WSAGetLastError();
                         SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str());                                             
                         break;
               }
  }
}
//prüfen welche ClientSockets im fd_set sind:
for(unsigned short i = 0; i<MAX_CLIENTS;i++)
{
             if(clients[i]==INVALID_SOCKET)
             {
                          continue;//ungültig, =>weitermachen(i++)
             }
             if(FD_ISSET(clients[i],&fdset))
             {
                           rc = recv(clients[i],buf,256,0);
                           //prüfen, ob Verbindung besteht, oder Fehler:
                           if(rc==0 || rc==SOCKET_ERROR)
                           {
                                  str_fortschritt+="\r\n";
                                  str_fortschritt+="Client ";
                                  str_fortschritt+=i;
                                  str_fortschritt+=" hat die Verbindung abgebrochen.";
                                  SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str());  
                                  closesocket(clients[i]);
                                  clients[i]=INVALID_SOCKET; //Platz freimachen
                           }
                           else
                           {
                                  buf[rc]='\0';
                                  printf("Client %d hat dolgendes gesandt: %s\n",i,buf);
                                  sprintf(buf2, "Du mich acuh %s",buf);
                                  send(clients[i],buf2,(int)strlen(buf2),0);
                           }
             }
}   //FOR 
} //WHILE



} //hStart
    }//switch(messages)

    return 0;
}//CALLBACKPROC.

Vielen Dank für die Mühen schoneinmal!
lg
kickerxy
 
Wenn ich das richtig sehe bleibt dein Programm bei "select()" stehen, den Select warrtet darauf bis der Socket bereit ist. Das Problem kannst du übergeben, in dem du einen Sinnvolen letzten Parameter übergibst, damit select sofort abbricht.
der Part dürfte dann in etwa so aussehen:
C++:
timeval t_time
t_time.tv_sec = t_time.tv_usec = 0;
rc = select(0,&fdset,NULL,NULL,&t_time);

mfg
SGSSGene
 
Vielen Dank! Ich denke, dass bringt mich schon einen großen Schritt weiter!
Ich habs eingebaut, hab auch mal ne variable in der while Schleife hochzählen lassen und in eine .txt schreiben lassen, deshalb weiß ich, dass er jetzt die whileschleife immerwieder ausführt und nicht mehr bei select stehenbleibt.
Dennoch nimmt er keinen Client an, zumindestens denke ich das..., obwohl im client "verbunden" steht, hier der Auschnitt vom Client:
Code:
  rc=connect(s,(SOCKADDR*)&addr,sizeof(SOCKADDR));
  if(rc==SOCKET_ERROR){//...}else{//->Verbunden}
Der Server jedoch ist in der whileschleife und reagiert nicht mehr, und zeigt auch nicht an, dass ein Client connected hat/will.


#edit: mir ist grade noch etwas aufgefallen:
Wenn ich ein folgendes mache:(also ein boolean auswerte:)
Code:
#include....
....
bool verbunden = false;
....
int WINAPI WinMain....
.....
while(1){
if(verbunden==true){
break;
}else{
FD_ZERO(&fdset); //Inhalt leeren
 FD_SET(acceptSocket, &fdset);  //Den Socket der Verbindungen annimt hinzufügen

 //Alle gültigen(!=INVALID_SOCKET)client sockets hinzufügen:
        for(unsigned short i=0;i<MAX_CLIENTS;i++)
        {
                     if(clients[i]!=INVALID_SOCKET)
                         {
                            FD_SET(clients[i],&fdset);
                         }
        }
   
        timeval t_timet_time;
        t_timet_time.tv_sec=t_timet_time.tv_usec=0;
        rc = select(0,&fdset,NULL,NULL,&t_timet_time);
if(rc==SOCKET_ERROR)
{
 
       str_fortschritt+="\r\n";
       str_fortschritt+="select-Fehler, Code:";
       int vy = WSAGetLastError();
       char pq[256];                                 //int ->char Konvertierung!
       sprintf(pq, "%d",vy);
       str_fortschritt+=pq;
       SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str());
       return 1;
}
//wenn accepsocket im fd_set ist und genügend platz => verbindung annehmen
if(FD_ISSET(acceptSocket,&fdset))
{
  //freien Platz suchen
  for(unsigned short i = 0; i< MAX_CLIENTS;i++)
  {
               if(clients[i]==INVALID_SOCKET)
               {
                        clients[i]=accept(acceptSocket,NULL,NULL);
                         str_fortschritt+="\r\n";
                         str_fortschritt+="Neuen Client ";
                         str_fortschritt+=i;
                         str_fortschritt+=" angenommen.";
                         str_fortschritt+=WSAGetLastError();
                         SendMessage(hFortschritt, WM_SETTEXT, 0, (LPARAM)str_fortschritt.c_str());        
                         verbunden = true;                                    
                         break;
               }
  }
}
läuft es! Er nimmt einen neuen Client an, bricht dann natürlich ab, aber immerhin einen kann er jetzt annehmen ;)
Nun hab ich warscheinlich nur noch das Problem, dass er sich in der whileschleife zu sehr auslastet?

lg
kickerxy
 
Zuletzt bearbeitet:
Hallo,

Ich habe mir aus diversen Foren und Tutorial-Seiten einen Server und einen Client auf CMD-Fenster Basis ge*****t. Nun bin ich dabei den Server unter WinApi du *****en, nur weiß ich net wo ich meine select()-Schleife einbaun sollte... Kann mir jemand helfen****

Hier wären meine Source-Dateien:
http://www.megaupload.com/?d=T5UMOU7T

mfg. Poseidon
 
So einige schreiben immer Sternchen (*****), was soll das heißen****

Willst du etwa von der Konsolenanwendung zur richtigen Windows-Applikation portieren?
Wann willst du denn den Code ausführen, beim Start? Nach einer Betätigung eines Button?
 
Zurück