在多线程聊天应用程序中显示带有fgets的命令提示符

时间:2017-02-02 21:07:27

标签: c multithreading chat fgets

我有一个命令行的聊天应用程序,但我似乎无法弄清楚如何显示"输入消息:"提示每个消息条目。这是一个非常简单的问题,但多线程和客户端/服务器关系让我失望。

客户端代码:

#define PORT 12000
#define BUFFER 4096

void * receive(void * socket) {
    int socket_fd, response;
    char buffer[BUFFER];
    socket_fd = (int) socket;
    while(true) {
        response = recvfrom(socket_fd, buffer, BUFFER, 0, NULL, NULL);
        if (response) {
            printf("Server: %s", buffer);
        }
    }
}

int main(int argc, char**argv) {
    struct sockaddr_in address, cl_addr;
    char * server_address;
    int socket_fd, response;
    char buffer[BUFFER];
    pthread_t thread;

    if (argc < 2) {
        printf("Usage: client [IP Address]\n");
        exit(1);
    }

    server_address = argv[1];
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = inet_addr(server_address);
    address.sin_port = PORT;
    socket_fd = socket(AF_INET, SOCK_STREAM, 0);

    response = connect(socket_fd, (struct sockaddr *) &address, sizeof(address));
    if (response < 0) {
        printf("Failed to connect\n");
        exit(1);
    }

    printf("Connected\n");

    // Create new thread to receive messages
    pthread_create(&thread, NULL, receive, (void *) socket_fd);

    // Get message from stdin and send to server
    printf("Enter a message: ");
    while (fgets(buffer, BUFFER, stdin) != NULL) {
        sendto(socket_fd, buffer, BUFFER, 0, (struct sockaddr *) &address, sizeof(address));
    }

    close(socket_fd);
    pthread_exit(NULL);
    return 0;
}

问题是&#34;输入消息:&#34;只显示一次。我尝试在while(fgets)循环中添加它,它成功地将提示放在客户端写入的每一行上,但是当服务器发送内容时,它会被抛弃。

Connected
Enter a message: foo
Enter a message: bar
Enter a message: Server: foo
Server: bar

我尝试在各个地方添加换行符并在receive函数后添加另一个提示符,但无论我做什么,总会有一些边缘情况会让人感到困惑。有没有办法只给fgets一个默认提示或什么?我花了太多时间在一些应该如此简单的事情上。

1 个答案:

答案 0 :(得分:1)

  

有没有办法让fgets给出默认提示符?

不是我知道的,除非您想开始使用像ncurses这样的库来进行更高级的终端管理(对于玩具程序,你可能不会这样做)。

你能做的是:

  1. fflush(stdout);来电后立即致电printf("Enter a message: ");,强制立即显示提示的文字(而不是仅在打印下一个换行符后)。

  2. 将一个回车符放在server-printf()的前面,例如printf("\rServer: %s\n", buffer);这会将终端的文本光标移回到行的开头,这样server-printf()文本将覆盖提示而不是附加到它。 (请注意,如果您的服务器文本不够长,您可能必须在末尾添加一些额外的空格以确保所有提示的文本都被覆盖)