0

TCP経由で通信するC言語の単純なクライアントおよびサーバープログラムがあります。クライアントはメッセージをサーバーに送信し、サーバーはそれをファイルに書き込みます。

クライアントがEOF文字を読み取るまで無期限にループし、サーバーがリクエストを処理し続ける必要があります。ただし、現時点では、ループに問題があります。ループなしで正常に動作しますが、クライアントに while(1) を配置すると、サーバーは最初の要求を正常に処理しますが、2 番目の要求は何もせず、3 番目の要求はパイプの破損エラーを引き起こします。これは、サーバーがソケットを閉じるのが早すぎるためだと思いますが、修正方法に行き詰まっています。

これが私のクライアントプログラムです:

#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; 
    }
4

1 に答える 1

2

main()サーバー コードの貼り付けが不適切で、複数のコピーが混在していることに注意してください。

accept()サーバーでは、クライアント接続を受信するために呼び出します。次に、接続を処理するスレッドを作成します。このスレッドは 1 つのメッセージだけを処理して終了しますが、クライアントが十分な数のメッセージを受け取るまで、クライアントからのすべてのメッセージを処理することになっています。

そのため、サーバー スレッドにループを配置して、複数のメッセージを処理できるようにする必要があります。

サーバーを実行したとき、スレッドによって処理された最初のメッセージは正しく受信されましたが (メッセージは "hello" と表示されます)、不適切な形式であると報告されました (メッセージEntry not well formed.)。OS-X上で動作。

次の行にも注意してください。

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

「!」は使用しないでください。定数 PTHREAD_CREATE_DETACHED の前。

于 2012-10-28T23:15:45.023 に答える