带有套接字通信的stdout上打印的残留字符

时间:2015-08-05 10:05:55

标签: c linux sockets tcp system-calls

在套接字TCP通信中,我有一个服务器和一个客户端。两者都可以读取和写入套接字。

代码是用C语言编写的,使用Linux系统调用recvwrite

recv将收到的字符串保存在:

char message_array[2000];

另一个具有相同维度的数组用作write进程的源。

在读取和写入过程之后,执行以下操作,以清除所有数组元素:

memset(&message_array, 0, sizeof(message_array));

此外,在每次写入和每次读取过程中,fflushstdin都会执行stdout

服务器在其stdout上打印它写的内容和收到的内容。

如果我从两个终端发送小消息(“你好”,“嗨”),即使多次(18-20),所有似乎都能正常工作。但是,如果我尝试发送更长的消息(超过5个字符,但短于2000!),服务器端有一些奇怪的行为:它打印从客户端收到的消息,但随后插入随机数的尾随字符以前的消息。例如,我有:

CLIENT MESSAGE: hello1
SERVER MESSAGE: hello2
CLIENT MESSAGE: hello3
SERVER MESSAGE: hello4 
CLIENT MESSAGE: some other characters5
SERVER MESSAGE: hello6
CLIENT MESSAGE: a long phrase 7
ters5

在几条消息之后,上一个消息中的5个字符ters5在实际消息之后显示为尾随字符,仅为a long phrase 7。 继续“对话”,其他意外的换行符和“旧”字符出现在服务器的stdout上。

读写例程的代码如下:

void *connection_handler_read(void *socket_read_desc)
{
    int read_sock = *(int*)socket_read_desc;
    int read_size;
    char remote_message[MAX_STRING_LEN];

    while( (read_size = recv(read_sock, remote_message, MAX_STRING_LEN, 0)) > 0 )
    {
        printf(remote_message);
        fflush(stdout);
    }

    free(socket_read_desc);
    connection_active = 0;
    return 0;
}

void *connection_handler_write(void *socket_write_desc)
{
    int write_sock = *(int*)socket_write_desc;
    char local_message[MAX_STRING_LEN];

    while( connection_active != 0 )
    {
        scanf ("%[^\n]%*c", local_message);
        write(write_sock, local_message, strlen(local_message));
        memset(&local_message, 0, sizeof(local_message));
        fflush(stdin);
    }

    free(socket_write_desc);
    return 0;
}

在成功创建新的套接字连接之后,main中的这两个函数作为带pthread_create的线程调用(因此,在成功accept之后)。它们显然在同一个插座上运行。

我的问题是:

1)这是软件问题还是套接字问题?

2)除了memsetfflush之外,我应该遵循哪种技巧?

2 个答案:

答案 0 :(得分:2)

  1. 在重新使用之前,读取端不会将用于读取的缓冲区归零。宣言时char remote_message[MAX_STRING_LEN] = {0};和阅读后memset(remote_message, 0, sizeof(remote_message);

  2. memset(&local_message, 0, sizeof(local_message)); - > memset(local_message, 0, sizeof(local_message));

  3. 请记住TCP(您使用的是TCP吗?)不是面向消息的协议。 read()可以(并最终将)返回1个字节与编写器到目前为止发送的数量之间的任何数据量。如果您需要面向行的协议/输出,请扫描读取数据'\ n'并且不要在scanf()中将其删除。

  4. 其他:

    • 你是否在某个地方的套接字描述符上调用close()
    • 为什么要释放int *参数?它们是否真的从具有malloc的堆中分配?

答案 1 :(得分:2)

connection_handler_read()中,您阅读了strlen()个字符,而memset()没有缓冲到'\0'。您在strlen()中发送的所有字符都是connection_handler_write()个字符,并且不计入尾随'\0'。在读取端缓冲区可能包含一些未初始化的字符。