IPC中使用套接字

时间:2017-01-24 14:06:50

标签: c sockets

我正在尝试编写一个最多可以处理5个并发客户端的服务器 每当客户端成功连接到服务器&客户端数量小于或等于5,服务器发送欢迎消息,生成一个5位唯一随机数用于标识该客户端,将此号码发送给客户端并在控制台中打印此号码。如果客户端数量往往大于5,然后对于每个新请求,它只发送一条消息"连接限制超过"给客户&关闭连接。
客户端只打印服务器发送的消息 我面临的问题是,随机数没有正确传播到客户端。客户端打印的次数与服务器生成的数量相同,但客户端只打印0次(作为存储传入的变量)该随机数的值初始化为0) 这背后的原因可能是什么?

以下是客户端和服务器的代码: 服务器:

/* 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

1 个答案:

答案 0 :(得分:2)

问题是TCP是面向流的协议,而不是面向数据包。所以可能会发生

  • 客户端的第一个read()读取服务器的第一个write()发送的内容(“欢迎”)
  • 客户端的第二个read()读取服务器发送的第二个write()(您的号码)

这是您所期望的以及有时会发生的事情。

但是,也可能是客户端立即读取两次写入服务器的数据!这通常发生在

  • 服务器将两次写入聚合为单个tcp-packet
  • 或客户端在两个带有数据的tcp段到达后读取数据

您无法确定会发生什么,也不能依赖任何特定行为。

如何解决此问题仅取决于您的协议。如果第一条消息始终为“Welcome \ n”,则首先尝试只读取8个字节。如果你碰巧读到n&lt; 8个字节,您必须重试并读取8-n个字节以获取剩余的消息。随后读取sizeof(received_int)个字节,同时监视接收的实际字节数。

如果消息长度可变,则必须使用某种类型的帧,如前面的长度字节或类似的内容。