Avatar billede tdh1309 Juniormester
18. marts 2003 - 08:56 Der er 11 kommentarer og
1 løsning

Socket programmering

Jeg har lavet en simpel webserver. Og den kører nogenlunde. Dog et lille problem - den æder 40% af cpu tiden. Jeg anvder NON-Blocking sockets og SELECT !!!
Nogle konstruktive forslag til hvordan prob. løses?

MVH

Thomas Hansen
Nedenfor er min source:
void WebServer(void)
{
  int servSock;                    // Socket descriptor for server
  int clntSock;                    // Socket descriptor for client
  struct sockaddr_in echoServAddr; // Local address
  struct sockaddr_in echoClntAddr; // Client address
  unsigned short echoServPort;    // Server port
  int servLen;                    // Length of server address data structure 
  int n_received;                      //
  fd_set fd_read, fd_write;
  long arg;
  typedef struct timeval
  {
    int tv_sec;    // second
    int tv_usec;  // microseconds
  } TIMEVAL;
  //timeval select_to;
  // int visitcount = 1;
  TIMEVAL select_to;
 
  echoServPort = 80;              // Port 80 - WWW
 
   
  // Create socket for incoming connections
  if ((servSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    return;
 
  // Construct local address structure
  memset(&echoServAddr, 0, sizeof(echoServAddr));  // Zero out structure
  echoServAddr.sin_family = AF_INET;                // Internet address family
  echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY); // Any incoming interface
  echoServAddr.sin_port = htons(echoServPort);      // Local port

  // Bind to the local address
  if (bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
    DieWithError("bind() failed");
 
  // Set socket to nonblocking
  arg = 1;    // enables non blocking mode
  if (ioctlsocket(servSock, FIONBIO,(PFDWORD)&arg)!= 0)  // All options off
  {
    closesocket(servSock);
    return;
  }
 
  // Mark the socket so it will listen for incoming connections
  if (listen(servSock, MAXPENDING) < 0)
    DieWithError("listen() failed");
 
  while(1)
    {     
      // Socket list for select is set up here !
      FD_ZERO(&fd_read);               
      FD_SET(servSock, &fd_read);
     
      // Wait for connection to be ready !
      if (select(1,(PFDSET)&fd_read,(PFDSET)0,(PFDSET)0,(PTIMEVAL)0) !=1)
        continue;
       
      // Accept available connected socket !
      servLen = sizeof((echoClntAddr));
      //if ((clntSock = accept(servSock, (PSOCKADDR)&echoClntAddr,(PFINT)&servLen))<0)
      if ((clntSock = accept(servSock, (PSOCKADDR)&echoServAddr,(PFINT)&servLen))<0)  // Tvivl om echoServAdr?
        continue;
     
      // Set socket to nonblocking mode
      // Force recv to return an error if no data is available.
      // Force send to return an error if it needs to block ->
      // send needs only to block if it can't fit all output data into output window.
      arg = 1;    // enables non blocking mode
      if (ioctlsocket(clntSock, FIONBIO,(PFDWORD)&arg)!= 0)  // All options off
      {
          closesocket(clntSock);
        continue;
      }
      // Set up socket list for select
      FD_ZERO(&fd_read);
      FD_SET(clntSock,&fd_read);
     
      // Wait for any data to be available
      if (select(1,(PFDSET)&fd_read,(PFDSET)0, (PFDSET)0,(PCTIMEVAL)0)!=1)
      {
        closesocket(clntSock);
        continue;
      }
           
      // Get data and ....
      while ((n_received = recv(clntSock,buf,BUFSIZE,0))>0)
      {
          // set up socket list for select
          FD_ZERO(&fd_write);
          FD_SET(clntSock,&fd_write);
         
          // Wait 20 sec. for previos sent to complete. ie. waits until all ouput data has been asked !
          select_to.tv_sec  = 90;
          select_to.tv_usec = 0;
          if (select(1,NULL,(PFDSET)&fd_write,NULL,(PCTIMEVAL)&select_to) != 1)
          //if (select(1,NULL,(PFDSET)&fd_write,NULL, NULL) != 1)
          {
            closesocket (clntSock);
            continue;              // select error
          }
         
          // send output data
          send(clntSock,defaultside, strlen(defaultside),0);
         
          // setup socket list for select !
          FD_ZERO(&fd_read);
          FD_SET(clntSock,&fd_read);
         
          // Wait for any data to be available
          if (select(1,(PFDSET)&fd_read,(PFDSET)0, (PFDSET)0,(PCTIMEVAL)0)!=1)
        {
          closesocket(clntSock);
          continue;
        }
        closesocket(clntSock);
        printf("clntSock Close\n");
      }
      close(servSock);     
    }
   
    /* NOT REACHED */
}
Avatar billede morw Nybegynder
18. marts 2003 - 09:04 #1
Lytter med...
Avatar billede tdh1309 Juniormester
18. marts 2003 - 09:11 #2
Jeg havde nu hellere set en løsning *S*
Avatar billede morw Nybegynder
18. marts 2003 - 09:16 #3
Jeg ved desværre næsten intet om sockets. Jeg er ved at bestille en bog om det, kender du nogle gode bøger?

Jeg synes dog du har mange selects? Et eksempel jeg så på havde kun en select.

Kender du: http://www.ecst.csuchico.edu/~beej/guide/net/html/
Avatar billede tdh1309 Juniormester
18. marts 2003 - 09:17 #4
Prøv dette link: http://www.lowtek.com/sockets/
Det er udemærket. Bøger - jeg er ikke faldet over en super bog endnu
Avatar billede segmose Nybegynder
18. marts 2003 - 09:25 #5
// Wait for connection to be ready !
      if (select(1,(PFDSET)&fd_read,(PFDSET)0,(PFDSET)0,(PTIMEVAL)0) !=1)
        continue;

Er problemet ikke at du venter 0 på hver select?

derved får du busy waiting, som æder din cpu tid. Hvorfor har du ventetid 0
her?
Avatar billede tdh1309 Juniormester
18. marts 2003 - 09:33 #6
Det kan måske tænkes at min begrænsede erfarring skinner igennem.
Jeg prøver lige lidt forskelligt - og vender tilbage...
Avatar billede tdh1309 Juniormester
18. marts 2003 - 09:51 #7
Jeg har nu forsøgt at ændre ventetiden til 1. sek.
Ved at:
// Wait 20 sec. for previos sent to complete. ie. waits until all ouput data has been asked !
          select_to.tv_sec  = 1;  // ny
          select_to.tv_usec = 0;  // ny
         
          // Wait for any data to be available
          if (select(1,(PFDSET)&fd_read,(PFDSET)0, (PFDSET)0,(PCTIMEVAL)&select_to)!=1)  // ændring ->&select_to
        {
          closesocket(clntSock);
          continue;
        }

Det giver dog på ingen måde forbedringer i performence (desværre)
Er det selve min opbygning der er forkert?
Avatar billede segmose Nybegynder
18. marts 2003 - 09:59 #8
Det var dog her jeg tænkte, hvis der ikke er noget starter du bare forfra i while.

// Wait for connection to be ready !
      if (select(1,(PFDSET)&fd_read,(PFDSET)0,(PFDSET)0,(PTIMEVAL)0) !=1)
        continue;
Avatar billede segmose Nybegynder
18. marts 2003 - 10:27 #9
Virker dit program ellers?

hvis man ser på beej's beskrivelse af select kunne man godt tro at alle dine

select(1, xxx,xxx,xxx)

skulle være select(max(clntSock, servSock)+1, xxx,xxx,xxx)

da hans fd altid er det højest fd nr + 1.
Avatar billede tdh1309 Juniormester
18. marts 2003 - 10:30 #10
Jeg har faktisk kigget på Beejs - og har også forsøgt med 'hans stil' den virker heller ikke. Jeg begynder at frygte det er mine protokoller der er et problem med....
Avatar billede tdh1309 Juniormester
18. marts 2003 - 11:01 #11
Det virker slet ikke
Avatar billede morw Nybegynder
18. marts 2003 - 15:07 #12
Dette projekt indeholder sikkert noget spændende:

http://www.acme.com/software/thttpd/
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester