使用tcp套接字时的数据转换模式是什么?

时间:2013-09-24 14:29:55

标签: c sockets

我有两个服务器代码:

  1. 第一台服务器:每次向客户端发送一个字符,直到字符串结束

    int
    main(int argc, char **argv)
    {
        int                 listenfd, connfd;
        struct sockaddr_in  servaddr;
        char                buff[MAXLINE];
        time_t              ticks;
            char                            temp[1];
            int                             i = 0;
    
        listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    
        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family      = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port        = htons(9999); /* daytime server */
    
        Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
    
        Listen(listenfd, LISTENQ);
    
        for ( ; ; ) {
            connfd = Accept(listenfd, (SA *) NULL, NULL);
    
            ticks = time(NULL);
            snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
    
            for(i = 0; i < strlen(buff); i++)
            {
                temp[0] = buff[i];
                Write(connfd, temp, strlen(temp));
            }
    
            Close(connfd);
        }
    }
    
  2. 第二台服务器:向客户端发送字符串

    int
    main(int argc, char **argv)
    {
        int                 listenfd, connfd;
        struct sockaddr_in  servaddr;
        char                buff[MAXLINE];
        time_t              ticks;
            char                            temp[1];
            int                             i = 0;
    
        listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    
        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family      = AF_INET;
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
        servaddr.sin_port        = htons(9999); /* daytime server */
    
        Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));
    
        Listen(listenfd, LISTENQ);
    
        for ( ; ; ) {
            connfd = Accept(listenfd, (SA *) NULL, NULL);
    
            ticks = time(NULL);
            snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
    
            Write(connfd, buff, strlen(buff));
            Close(connfd);
        }
    }
    
  3. 客户端:接收服务器发送的字符

    int
    main(int argc, char **argv)
    {
        int                 sockfd, n;
        char                recvline[MAXLINE + 1];
        struct sockaddr_in  servaddr;
            int count = 0;
    
        if (argc != 2)
            err_quit("usage: a.out <IPaddress>");
    
        if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
            err_sys("socket error");
    
        bzero(&servaddr, sizeof(servaddr));
        servaddr.sin_family = AF_INET;
        servaddr.sin_port   = htons(9999);  /* daytime server */
        if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)
            err_quit("inet_pton error for %s", argv[1]);
    
        if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
            err_sys("connect error");
    
        while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {
            recvline[n] = 0;    /* null terminate */
                    count++;
            if (fputs(recvline, stdout) == EOF)
                err_sys("fputs error");
        }
        if (n < 0)
            err_sys("read error");
            printf("read time:%d\n", count);
    
        exit(0);
    }
    
  4. 结果是变量计数的输出都是1.我的问题是为什么第一个服务器的输出为1,我认为结果应该是第一个服务器的strlen(buff)?

    PS:我在同一台机器上运行服务器和客户端。

1 个答案:

答案 0 :(得分:2)

TCP是一种流协议。因此,一方的写入次数不会导致另一方的读取数量相同,因为协议不保留有关如何写入套接字的信息。

通常,在发送方面,如果您向套接字写入更多数据,则可以在发送数据包之前出现延迟,以便可以将更多数据填充到同一个数据包中。其中一个原因是编写糟糕的服务器可能会使用单字节数据包充斥网络。

在接收方,协议不知道为什么您的数据可能作为单独的数据包到达,它可能因为MTU而被拆分,它可能已经被某些数据包检测软件或设备重新组装了,所以无论何时从套接字读取,它都会为您提供尽可能多的数据,无论它是如何发送给您的。

在您的设置中的本地计算机上,可能是客户端在服务器写入时甚至没有运行,所以即使没有在发送方缓冲,它也不会在服务器写入所有内容之后开始读取,因此它将会一次性阅读所有内容。或者不是,你可能运气不好,你的服务器被抢占的时间足够长,你的内核中的TCP实现认为你将不再发送任何数据,向客户端发送一个字节,客户端被安排在服务器再次运行之前运行,客户端在第一次读取时只接收一个字节。