2017-01-24 6 views
1

最大5つの同時クライアントを処理できるサーバーを作成しようとしています。
クライアントがサーバに正常に接続されると、クライアントの数は5以下です。サーバはウェルカムメッセージを送信し、そのクライアントを識別する5桁の一意の乱数を生成し、この番号をクライアントに送信し、この数をコンソールに表示します。クライアントの数が5を超える傾向にある場合、新しい要求ごとに、クライアントに「Connection Limit Exceeded」というメッセージを送信します。&は接続を閉じます。
クライアントは、サーバーから送信されたメッセージを出力します。
私が直面している問題は、乱数がクライアントに正しく伝播されていないことです。クライアントがサーバによって生成されたのと同じ番号を出力しますが、クライアントは何も出力しません。その乱数の値は0に初期化されます)。
これの背景には何がありますか?ここでソケットを使用したIPCでの予期しない出力

は、クライアントとサーバーのコードです: サーバー:

/* A simple server in the internet domain using TCP 
    The port number is passed as an argument 
    This version runs forever, forking off a separate 
    process for each connection 
*/ 
#include <stdio.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <time.h> 
#include <stdlib.h> 

void dostuff(int); /* function prototype */ 
void write_once (int sock); 
void error(const char *msg) 
{ 
    perror(msg); 
    exit(1); 
} 

int main(int argc, char *argv[]) 
{ 
    int sockfd, newsockfd, portno, pid, count = 0; 
    socklen_t clilen; 
    struct sockaddr_in serv_addr, cli_addr; 

    if (argc < 2) { 
     fprintf(stderr,"ERROR, no port provided\n"); 
     exit(1); 
    } 
    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); 
    if (bind(sockfd, (struct sockaddr *) &serv_addr, 
       sizeof(serv_addr)) < 0) 
       error("ERROR on binding"); 
    listen(sockfd,5); 
    clilen = sizeof(cli_addr); 
    while (1) { 
     newsockfd = accept(sockfd, 
       (struct sockaddr *) &cli_addr, &clilen); 
     if (newsockfd < 0) 
      error("ERROR on accept"); 
     pid = fork(); 
     count++; 
     if (pid < 0) 
      error("ERROR on fork"); 
     if (pid == 0 && count <=5) { 
      close(sockfd); 
      dostuff(newsockfd); 
      exit(0); 
     } 
     if (pid == 0 && count >= 5) { 
      close(sockfd); 
      write_once(newsockfd); 
      exit(0); 
     } 
     else close(newsockfd); 
    } /* end of while */ 
    close(sockfd); 
    return 0; /* we never get here */ 
} 

/******** DOSTUFF() ********************* 
There is a separate instance of this function 
for each connection. It handles all communication 
once a connnection has been established. 
*****************************************/ 
void dostuff (int sock) 
{ 
    int n; 
    char buffer[256]; 

    bzero(buffer,256); 
    n = write(sock,"Welcome\n",8); 
    if (n < 0) error("ERROR writing to socket"); 

    srand((unsigned int)time(NULL)); 
    int r = rand() % 90000 + 10000; 
    int converted_r = htonl(r); 

    n = write(sock, &converted_r, sizeof(converted_r)); 
    if (n < 0) error("ERROR writing to socket"); 
    printf("%d\n", r); 
} 

void write_once (int sock) 
{ 
    int n; 
    char buffer[256]; 
    bzero(buffer,256); 
    n = write(sock,"Connection Limit Exceeded!!",28); 
    if (n < 0) error("ERROR writing to socket"); 
} 

クライアント:

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

void error(const char *msg) 
{ 
    perror(msg); 
    exit(0); 
} 

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

    char buffer[256]; 
    if (argc < 3) { 
     fprintf(stderr,"usage %s hostname port\n", argv[0]); 
     exit(0); 
    } 
    portno = atoi(argv[2]); 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    if (sockfd < 0) 
     error("ERROR opening socket"); 
    server = gethostbyname(argv[1]); 
    if (server == NULL) { 
     fprintf(stderr,"ERROR, no such host\n"); 
     exit(0); 
    } 
    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); 
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
     error("ERROR connecting"); 

    bzero(buffer,256); 
    n = read(sockfd,buffer,255); 
    if (n < 0) 
     error("ERROR reading from socket"); 
    printf("%s\n",buffer); 

    n = read(sockfd, &received_int, sizeof(received_int)); 
    if (n < 0) 
     error("ERROR reading from socket"); 
    printf("%d\n", ntohl(received_int)); 
    close(sockfd); 
    return 0; 
} 

Reference

+3

TCP機能の読み取り(または書き込み)は、コードが正しく処理しない0を返すことがあります。また、要求されたバイト数よりも少なくなることがあります。これはエラーではありません。この場合、必要なだけ多くのバイトを受け取るまで関数を再度呼び出します。 http://stackoverflow.com/questions/666601/what-is-the-correct-way-of-reading-from-a-tcp-socket-in-c-cも参照してください。 – sb9

答えて

2

問題は、TCPは、ストリーム指向のプロトコルであり、ではないということですパケット指向。だから、(

  • クライアントの最初のread()が送信サーバー(「ようこそ」)の最初のwrite()
  • クライアントの第二read()は、サーバの第二write()が送信したもの読み込み何読み込むことが起こり得ますあなたの番号)

これはあなたが期待するものであり、時には何が起こるかです。

ただし、クライアントがというデータを読み取って、同時にサーバーの書き込みをにすることもできます。これは通常、

  • サーバーが単一のTCPパケットに2件の書き込みを集約
  • またはクライアントがデータを読み込む際のデータとの両方のTCPセグメントが

に到着した後、あなたは何を確認することはできませんが起こります特定の動作に依存することはできません。

これを修正する方法は、ご使用のプロトコルによって異なります。最初のメッセージが常に「ようこそ\ n」の場合は、最初に8バイトだけを読み取ろうとします。 n <の8バイトを読み取る場合は、残りのメッセージを取得するために8-nバイトを再試行して読み取る必要があります。続いてsizeof(received_int)バイトを読み込み、受け取った実際のバイト数も調べます。

メッセージの長さが可変であれば、前の長さバイトなどのような何らかのフレーミングを使用する必要があります。

関連する問題