TCP Server 多包发送问题

TCP Server multiple packet sending issue

我已经使用 linux tcp 套接字编写了服务器客户端程序。

客户端向服务器请求当前目录文件列表 发送 ls 命令

server replies all the list of files in server dir.
I was testing it for more files in server working dir.

server response format in the buffer
file/dir [tab] file_name [tab] file_change_time
for each 1000 files to client.

服务器发送代码:

#define BUFSIZE 1400

void lsfun(node_t *pclient)
{
    DIR *directory;
    int status;
    int cpylen = 0;
    int msglen = 0;
    unsigned int tt_count = 0;
    unsigned int no_files = 0;
    unsigned int no_sends = 0;
    int clientfd = *(pclient->client_socket);
    char *filectime;
    char *buffer = malloc(BUFSIZE * sizeof(char));
    char *tmp = malloc(BUFSIZE * sizeof(char));
    char ending[] = "#####";
    struct dirent *dir;
    struct stat type;

    pthread_mutex_lock(&lock);
    chdir(pclient->pwd);
    directory = opendir(".");
    pthread_mutex_unlock(&lock);

    if(tmp == NULL || buffer == NULL)
        printf("malloc error for client conn:%d\n", clientfd);

    if(directory)
    {
        while((dir = readdir(directory)) != NULL)
        {
            if(!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."))
                continue;
            status = stat(dir->d_name, &type);

            if(status == 0)
            {
                filectime = ctime(&type.st_ctime);

                if(dir->d_type != DT_REG)
                    cpylen = snprintf(tmp, BUFSIZE, "dir\t%s\t%s", dir->d_name, filectime);
                else
                    cpylen = snprintf(tmp, BUFSIZE, "file\t%s\t%s", dir->d_name, filectime);

                tmp[cpylen] = 0;

                if((cpylen + msglen) < BUFSIZE)
                {
                    strlcpy(buffer + msglen, tmp, cpylen);
                    msglen += cpylen;
                    no_files += 1;
                }
                else
                {
                    tt_count += msglen;
                    printf("%s", buffer);
                    fflush(stdout);
                    send(clientfd, buffer, strlen(buffer), 0);
                    memset(buffer, 0, BUFSIZE + 5);
                    snprintf(buffer, cpylen, "%s", tmp);
                    msglen = cpylen;
                    cpylen = 0;
                    no_files += 1;
                    no_sends += 1;
                }
            }
            else
            {
                cpylen = snprintf(buffer + msglen, BUFSIZE, "%s%s\n", "file stat error:", dir->d_name);
                msglen += cpylen;
            }
            memset(tmp, 0, BUFSIZE);
        }
    }

    cpylen = strlen(buffer);
    if(msglen == cpylen)
        send(clientfd, buffer, strlen(buffer), 0);

    send(clientfd, ending, strlen(ending), 0);      //sending msg ending for client read to close

    printf("\nlssize :%d\tnofile:%d, msglen:%d\tcpylen:%d\tno_sends:%d\n", tt_count + msglen, no_files, msglen, cpylen, no_sends);

    free(tmp);
    free(buffer);
    closedir(directory);
}


客户端接收码:

#define BUFSIZE 1400
while(true)
{
    msgsize = read(socketfd, buffer, BUFSIZE);
    buffer[msgsize] = 0;
    snprintf(ending, 6, "%s", buffer + (strlen(buffer) - 5));

    if(strcmp(ending, "#####") == 0)
    {
        buffer[strlen(buffer) - 5] = 0;

        if(buffer[strlen(buffer) - 1] == '\n')
            printf("%s", buffer);
        else
            printf("%s\n", buffer);
        fflush(stdout);

        break;
    }
    else
    {
        printf("%s", buffer);
        memset(buffer, 0, BUFSIZE);
    }
}

服务器回放调试打印:

lssize :19931 nofile:501, msglen:437 cpylen:39 no_sends:14

为什么我只收到来自
的两个数据包而不是 14 个数据包 每个大约 1400 字节的服务器数据包?

哪里错了?

也欢迎任何代码改进建议。

除了评论中指出的错误之外,您的代码还有更多基本问题,这些问题过于广泛,无法仅进行评论。

此代码暗示多线程使用:

pthread_mutex_lock(&lock);
chdir(pclient->pwd);
directory = opendir(".");
pthread_mutex_unlock(&lock);

BUT,此代码假定当前工作目录始终是当前函数的 pclient->pwd:

 status = stat(dir->d_name, &type);

如果在循环 运行 时另一个线程调用 chdir() 到另一个目录则不会,所以你的结果

stat() 始终检查整个进程当前工作目录的相对路径。在您发布的代码中,哪些可以更改。

要遵循的一个好规则是,如果您正在编写多线程代码,从不 做会改变进程的任何全局 属性 的事情。

你使用snprintf()也是bug-prone。例如:

cpylen = snprintf(buffer + msglen, BUFSIZE, "%s%s\n", "file stat error:", dir->d_name);

根据 7.21.6.5 The snprintf function, paragraph 2 of the C11 standard(加粗我的):

The snprintf function returns the number of characters that would have been written had n been sufficiently large, not counting the terminating null character, or a negative value if an encoding error occurred. Thus, the null-terminated output has been completely written if and only if the returned value is nonnegative and less than n.

您盲目地假设您对 snprintf() 的每一次调用都有效。如果对 snprintf() 的任何一次调用失败,您的消息内容将非常不确定,并且您对 msglen 的值将不会准确反映缓冲区的内容。

这意味着此代码不会发送任何内容:

cpylen = strlen(buffer);
if(msglen == cpylen)
    send(clientfd, buffer, strlen(buffer), 0);