2012-10-28 48 views
0

我有一個簡單的C客戶端和服務器程序,通過TCP進行通信。客戶端將消息發送到服務器,服務器將其寫入文件。客戶端服務器循環導致損壞的管道 - C

我需要客戶端無限循環,直到它讀取一個EOF字符,並讓服務器繼續爲請求提供服務。但是,目前我正在解決循環問題。它工作正常,沒有任何循環,但是當我在客戶端中放置一段時間(1)時,服務器爲第一個請求提供服務,但第二個服務器沒有做任何事情,第三個服務器導致管道錯誤。我認爲這是因爲服務器過早關閉了套接字,但我堅持如何解決它。

這裏是我的客戶端程序:

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


#define BUFFERLENGTH 256 

/* displays error messages from system calls */ 
void error(char *msg) 
{ 
    perror(msg); 
    exit(0); 
} 

int main(int argc, char *argv[]) 
{ 
    int sockfd, portno, n; 
    struct sockaddr_in serv_addr; 
    struct hostent *server; 

    char buffer[BUFFERLENGTH]; 
    if (argc < 3) { 
     fprintf (stderr, "usage %s hostname port\n", argv[0]); 
     exit(1); 
    } 

    /* create socket */ 
    portno = atoi (argv[2]); 
    sockfd = socket (AF_INET, SOCK_STREAM, 0); 
    if (sockfd < 0) 
     error ("ERROR opening socket"); 

    /* enter connection data */ 
    server = gethostbyname (argv[1]); 
    if (server == NULL) { 
     fprintf (stderr, "ERROR, no such host\n"); // error message for when the provided hostname doesn't exist. 
     exit (1); 
    } 
    bzero ((char *) &serv_addr, sizeof(serv_addr)); 
    serv_addr.sin_family = AF_INET; 
    bcopy ((char *)server->h_addr, 
     (char *)&serv_addr.sin_addr.s_addr, 
     server->h_length); 
    serv_addr.sin_port = htons (portno); 

    /* connect to the server */ 
    if (connect (sockfd, (struct sockaddr *) &serv_addr, sizeof (serv_addr)) < 0) 
     error ("ERROR connecting"); 
while(1){ 
    /* prepare message */ 
    printf ("Please enter the message: "); 
    bzero (buffer, BUFFERLENGTH); 
    fgets (buffer, BUFFERLENGTH, stdin); 

    /* send message */ 
    n = write (sockfd, buffer, strlen(buffer)); 
    if (n < 0) 
     error ("ERROR writing to socket"); 
    bzero (buffer, BUFFERLENGTH); 

    /* wait for reply */ 
    n = read (sockfd, buffer, BUFFERLENGTH -1); 
    if (n < 0) 
     error ("ERROR reading from socket"); 
    printf ("%s\n",buffer); 

} 
return 0; 
} 

和服務器代碼:

/* A threaded server which uses TCP to communicate with clients. 
     Passes the port number and a file name in as arguments. 
     Receives log entries from the clients and writes them to the file. */ 
    #include <stdio.h> 
    #include <sys/types.h> 
    #include <sys/socket.h> 
    #include <netinet/in.h> 
    #include <ctype.h> 
    #include <stdlib.h> 
    #include <strings.h> 
    #include <string.h> 
    #include <unistd.h> 
    #include <pthread.h> 

    #define BUFFERLENGTH 256 

    /* displays error messages from system calls */ 
    void error(char *msg) 
    { 
     perror(msg); 
     exit(1); 
    } 

    FILE *file; 
    int returnValue; 
    pthread_mutex_t mut; /* the lock */ 

    /* the procedure called for each request */ 
    void *processRequest (void *args) { 
     int *newsockfd = (int *) args; 
     char buffer[BUFFERLENGTH]; 
     int n, formed = 0; 

     n = read (*newsockfd, buffer, BUFFERLENGTH -1); 
     if (n < 0) 
     error ("ERROR reading from socket"); 

     printf ("Here is the message: %s\n",buffer); 
     pthread_mutex_lock (&mut); /* lock exclusive access to variable isExecuted */ 

     //const char* string = "hello world"; 
     char buffer2[256]; 
     char* walker; 
     int colon = 0; 


     strcpy(buffer2,buffer); 

    walker=buffer2; 

    while(colon == 0){ 

     if(*walker == ':'){ // if it encounters a colon will successfully exit the loop. 
      colon = 1; 
     } 
     if(*walker == '\0'){ // if it encounters the end of the string, will break the loop. 
      break; 
     } 
     if(isalnum(*walker)){ // if it's not an alphanumeric character then it will break the loop, otherwise it will continue. 
      walker++; 
    } else { 
    break;} 

    } 

    if(colon == 1){ // if the loop found a colon, then it will continue to search the rest of the string. 
     while(*walker >= 32 && *walker<= 126){ 
       ++walker; 
      if(*walker == '\n'){ 
       printf("Entry well formed.\n"); 
       fprintf(file,"%s",buffer); /*writes*/ 
        fclose(file); /*done!*/ 
       formed = 1; 
      } 
      } 
    } else{ 
     perror("Entry not well formed.\n"); 
    } 

     pthread_mutex_unlock (&mut); /* release the lock */ 

    if(formed==1){ 
     n = sprintf (buffer, "Message received and written to file.\n"); 
    }else{ 
     n = sprintf (buffer, "Message received but was not well formed and was not written to file.\n"); 
    } 
     /* send the reply back */ 
     n = write (*newsockfd, buffer, BUFFERLENGTH); 
     if (n < 0) 
     error ("ERROR writing to socket"); 

     close (*newsockfd); /* important to avoid memory leak */ 
     free (newsockfd); 

     returnValue = 0; /* cannot guarantee that it stays constant */ 
     pthread_exit (&returnValue); 
    } 



    int main(int argc, char *argv[]) 
    { 
     socklen_t clilen; 
     int sockfd, portno; 
     char buffer[BUFFERLENGTH]; 
     struct sockaddr_in serv_addr, cli_addr; 
     pthread_t *server_thread; 
     int result; 


     if (argc < 3) { 
      fprintf (stderr,"ERROR, arguments: port filename.\n"); /* Error message for if there isn't enough arguments. */ 
      exit(1); 
     } 


     /* create socket */ 
     sockfd = socket (AF_INET, SOCK_STREAM, 0); 
     if (sockfd < 0) 
      error("ERROR opening socket"); 
     bzero ((char *) &serv_addr, 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); 

     /* bind it */ 
     if (bind(sockfd, (struct sockaddr *) &serv_addr, 
        sizeof(serv_addr)) < 0) 
        error("ERROR on binding"); 

     /* ready to accept connections */ 
     listen (sockfd,5); 
     clilen = sizeof (cli_addr); 

     /* now wait in an endless loop for connections and process them */ 
     while (1) { 

      file = fopen(argv[2], "a"); 
      if (file == NULL) { 
      printf("I couldn't open results.txt for writing.\n"); 
      exit(0); 
      } 
      int *newsockfd; /* allocate memory for each instance to avoid race condition */ 
      pthread_attr_t pthread_attr; /* attributes for newly created thread */ 

      newsockfd = malloc (sizeof (int)); 
      if (!newsockfd) { 
     fprintf (stderr, "Memory allocation failed!\n"); 
     exit (1); 
      } 
      /* waiting for connections */ 
      *newsockfd = accept(sockfd, 
        (struct sockaddr *) &cli_addr, 
        &clilen); 
      if (*newsockfd < 0) 
     error ("ERROR on accept"); 
      bzero (buffer, BUFFERLENGTH); 

     /* create separate thread for processing */ 
     server_thread = malloc (sizeof (pthread_t)); 
     if (!server_thread) { 
     fprintf (stderr, "Couldn't allocate memory for thread!\n"); 
     exit (1); 
      } 

     if (pthread_attr_init (&pthread_attr)) { 
     fprintf (stderr, "Creating initial thread attributes failed!\n"); 
     exit (1); 
     } 

     if (pthread_attr_setdetachstate (&pthread_attr, !PTHREAD_CREATE_DETACHED)) { 
      fprintf (stderr, "setting thread attributes failed!\n"); 
     exit (1); 
     } 
     result = pthread_create (server_thread, &pthread_attr, processRequest, (void *) newsockfd); 
      if (result != 0) { 
     fprintf (stderr, "Thread creation failed!\n"); 
     exit (1); 
      } 


     } 
     return 0; 
    } 

回答

2

請注意,您的服務器代碼已被粘貼不好,包含main()多個副本混了。

在服務器中,您可以撥打accept()來接收客戶端連接。然後創建一個線程來處理連接。該線程只處理一條消息並退出,但它應該服務於來自客戶端的所有消息,直到客戶端擁有足夠的消息。

所以你需要在服務器線程中放置一個循環來允許它處理多條消息。

請注意,當我運行服務器時,線程處理的第一條消息被正確接收(消息讀取爲「hello」),但報告形成嚴重(消息Entry not well formed.)。在OS-X上運行。

還要注意行:

if (pthread_attr_setdetachstate (&pthread_attr, !PTHREAD_CREATE_DETACHED)) { 

不應該有 '!'在常量PTHREAD_CREATE_DETACHED前面。

+0

對不起,現在糾正了嚴重粘貼的服務器代碼。 格式良好/形式不正確是程序的一部分,字符串需要遵循語法寫入文件。 – user1781340

相關問題