yuesong-feng / 30dayMakeCppServer

30天自制C++服务器,包含教程和源代码
5.69k stars 742 forks source link

Day2 问题求助 #34

Open pxjl opened 2 years ago

pxjl commented 2 years ago

server的char buf[1024]改成char buf[2048]后server返回的消息会间隔一次,求教这是为什么

kyk@ubuntu:~/web_server/d2$ ./client 
9
message from server: 9
8
message from server: 
7
message from server: 8
6
message from server: 
5
message from server: 7
4
message from server: 
3
message from server: 6
2
message from server: 
1
message from server: 5

server.cpp

#include <sys/socket.h>
#include <arpa/inet.h>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>

void errif(bool condition, const char *errmsg)
{
    if (condition)
    {
        perror(errmsg);
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char const *argv[])
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    errif(sockfd == -1, "sock creat error");

    struct sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);

    errif(bind(sockfd, (sockaddr *)&serv_addr, sizeof(serv_addr)) == -1, "sock bind error");

    errif(listen(sockfd, SOMAXCONN) == -1, "sock listen error");

    struct sockaddr_in clnt_addr;
    socklen_t clnt_addr_len = sizeof(clnt_addr);
    bzero(&clnt_addr, sizeof(clnt_addr));

    int clnt_sockfd = accept(sockfd, (sockaddr *)&clnt_addr, &clnt_addr_len);
    errif(clnt_sockfd == -1, "sock accpt error");
    printf("new client fd %d! IP: %s Port: %d\n", clnt_sockfd, inet_ntoa(clnt_addr.sin_addr), ntohs(clnt_addr.sin_port));

    while (true)
    {
        char buf[2048];
        bzero(&buf, sizeof(buf));
        ssize_t read_size = read(clnt_sockfd, buf, sizeof(buf));
        if (read_size > 0)
        {
            printf("message from client fd %d: %s\n", clnt_sockfd, buf);
            write(clnt_sockfd, buf, sizeof(buf));
        }
        else if (read_size == 0)
        {
            printf("client fd %d disconnected\n", clnt_sockfd);
            close(clnt_sockfd);
            break;
        }
        else if (read_size == -1)
        {
            close(clnt_sockfd);
            errif(true, "socket read error");
        }
    }
    close(sockfd);
    return 0;
}

client.cpp

#include <sys/socket.h>
#include <arpa/inet.h>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>

void errif(bool condition, const char *errmsg)
{
    if (condition)
    {
        perror(errmsg);
        exit(EXIT_FAILURE);
    }
}

int main(int argc, char const *argv[])
{
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    errif(sockfd == -1, "sock creat error");

    struct sockaddr_in serv_addr;
    bzero(&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    serv_addr.sin_port = htons(8888);

    errif(connect(sockfd, (sockaddr *)&serv_addr, sizeof(serv_addr)) == -1, "connect error");

    while (true)
    {
        char buf[1024];
        bzero(&buf, sizeof(buf));                              //清空缓冲区
        scanf("%s", buf);                                      //从键盘输入要传到服务器的数据
        ssize_t write_bytes = write(sockfd, buf, sizeof(buf)); //发送缓冲区中的数据到服务器socket,返回已发送数据大小
        if (write_bytes == -1)
        { // write返回-1,表示发生错误
            printf("socket already disconnected, can't write any more!\n");
            break;
        }
        bzero(&buf, sizeof(buf));                            //清空缓冲区
        ssize_t read_bytes = read(sockfd, buf, sizeof(buf)); //从服务器socket读到缓冲区,返回已读数据大小
        if (read_bytes > 0)
        {
            printf("message from server: %s\n", buf);
        }
        else if (read_bytes == 0)
        { // read返回0,表示EOF,通常是服务器断开链接,等会儿进行测试
            printf("server socket disconnected!\n");
            break;
        }
        else if (read_bytes == -1)
        { // read返回-1,表示发生错误,按照上文方法进行错误处理
            close(sockfd);
            errif(true, "socket read error");
        }
    }

    return 0;
}
philipzhux commented 2 years ago

It's because at each loop of your client, you both send and receive 1024 bytes. However, each time the server receives a 1024 bytes of message, it would echo a 2048 bytes one. Therefore, it takes two loops on the client side to receive one echo, but you called scanf and send in every loop, not every other loop. The asymmetry accounts for the problem. You can solve it by not reading/sending the whole buffer but only strlen(buffer)+1 instead (it only works for string though).

define9 commented 1 year ago

对, 改成2048后就是那边两个循环顶这边一个循环, 你可以改成10240, 可以明显看到那边10个循环顶这1个, 可能不太懂, 我觉得他俩得一样