2

I have this program that i can run with a port number then in browser do something like localhost:port/image.jpg and it will open the image. However i want to try and do this using threads.

#include <stdio.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h>   
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>

#define BufferSize 1024 // for parsing request
#define BIG_ENUF 4096 // For request header

void error(char *); // prototype for quick error exit
int main(int argc, char *argv[]) // arv[1] has port #
{
 int sockfd, newsockfd, portno, clilen,Connect_Count=0;
  char buffer[BufferSize]; // for communicating with client
  char * BigBuffer; // for serving file to client
  int BufferNdx,n ;// workaday subscripts 
  char * TmpBuffer, *SavePtr, *FileName, *GetToken;
  pid_t pid; // for forks;
  FILE * F;  // for streaming file when GET served
  struct stat S;// to find file length 
  struct sockaddr_in serv_addr, cli_addr; 
// structs for client and server


   if (argc < 2) {  // looking for port # 
      fprintf(stderr,"ERROR, no port provided\n");
      exit(1);
   }
   sockfd = socket(AF_INET, SOCK_STREAM, 0);
 // specifies TCP IP flow 
   if (sockfd < 0)error("ERROR opening socket");
   memset( (char *) &serv_addr, 0, sizeof(serv_addr));
   portno = atoi(argv[1]);
   serv_addr.sin_family = AF_INET;  
   serv_addr.sin_addr.s_addr = INADDR_ANY;
   serv_addr.sin_port = htons(portno); // proper byte order
   if (bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
                error("ERROR on binding");
   GetToken = strtok_r(TmpBuffer," ",&SavePtr); 
 // And Now port is bound to socket for TCP / IP 
    while (Connect_Count < 10) // Limit on Number of Connections
      {listen(sockfd,5);
        clilen = sizeof(cli_addr);
        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
      // listen blocks until someone knocks and when we accept 

      // the client structure is filled by accept 
        if (newsockfd < 0) // exit server if bad accept 
        error( "ERROR on accept");
      // otherwise let's fork a process to do that work 
        pid = fork();
        if (pid < 0) error("bad fork\n");
        if (pid == 0) break;
      // to handle talking with client below
      //if parent, loop again to listen if more connections ? 
    }

 // ===================================================  
// Forked child 
     memset(buffer, 0,BufferSize);
     n = read(newsockfd,buffer,BufferSize-1); // This leaves null at end
    if (n < 0) error("ERROR reading from socket");

 printf("%s\n",(TmpBuffer=strtok_r(buffer,"\n",&SavePtr)));
 GetToken = strtok_r(TmpBuffer," ",&SavePtr); 
 printf("%s\n",GetToken); 
 GetToken = strtok_r(NULL," ",&SavePtr); 
 printf("%s After Get\n",GetToken); // file name token begins '/'
 GetToken++; // Point to first character of actual file name 
// now open the file and send it to client ? 
 if ((F =  fopen(GetToken,"r")) == NULL) error("Bad\n");
else printf("Good\n"); 
    int FileSize;
if ((fstat(fileno(F),&S)==-1)) error("failed fstat\n"); // Need file size 
FileSize = S.st_size;          
 char Response[BIG_ENUF];int HeaderCount=0;
HeaderCount=0;//Use to know where to fill buffer with sprintf 
    HeaderCount+=sprintf( Response+HeaderCount,"HTTP/1.0 200 OK\r\n");
    HeaderCount+=sprintf( Response+HeaderCount,"Server: Flaky Server/1.0.0\r\n");
    HeaderCount+=sprintf( Response+HeaderCount,"Content-Type: image/jpeg\r\n");
    HeaderCount+=sprintf( Response+HeaderCount,"Content-Length:%d\r\n",FileSize);
 //delimit header
    HeaderCount+=sprintf( Response+HeaderCount,"\r\n"); 
    fprintf(stderr,"HeaderCount %d and Header\n",HeaderCount);
    write(STDERR_FILENO, Response, HeaderCount);
    write(newsockfd,Response,HeaderCount); // and send to client
    BigBuffer = malloc(FileSize+2);
    fread(BigBuffer,1,FileSize,F);
    write(newsockfd,BigBuffer,FileSize);
    free(BigBuffer); 
// Now close up this client 
 close(newsockfd);
 return 0; 
}
// bad error routine
void error(char *msg)
{
   perror(msg);
   exit(1);
} 

I'm trying to convert these processes into a threads program. I'm very new to threads. But is the basic concept to move everything i have labeled under the child process to the thread function? and replace the forking with pthread_create s?

cage479
  • 43
  • 5
  • 1
    Basically yes. Everything after you check the file descriptor returned by `accept` should go into the function passed to `pthread_create`. Also you should pass the `newsockfd` value as an argument in `pthread_create`. You may also want to make the thread detached, as you probably won't wait for it to join. – Paul Rooney Apr 30 '15 at 02:18
  • @PaulRooney what does making a thread detached mean/do? – cage479 Apr 30 '15 at 02:41
  • It means that you are creating the thread then letting it run without worrying about when it will complete it's task, much like the forked processes you are already using. See [this](http://stackoverflow.com/questions/3756882/detached-vs-joinable-posix-threads) answer and [this](http://linux.die.net/man/3/pthread_detach) man page for some more details. – Paul Rooney Apr 30 '15 at 02:50
  • "*listen blocks until someone knocks and when we accept ...*". No, `listen()` never blocks, but `accept()` does. Having `listen()` in the `accept`-loop does not make any sense, at least if called with a constant argument. You want to move the call to `listen()` out of the accepting loop. – alk Apr 30 '15 at 14:12
  • I propose the the following test-case: Create an (image-)file on the server with a name >2000 characters long. Try pulling it via your browser. I bet this would fail. Probably some 100 characters will do already to make this fail. – alk Apr 30 '15 at 14:16
  • Also the code missed to close the (copy of) the accepting socket in the `fork()`ed-off process. – alk Apr 30 '15 at 14:18

0 Answers0