3

全部。

我对使用 P 线程库和 BSD 套接字的基于 unix 的聊天室有一个小问题。

此时,客户端可以连接到服务器,使用所需的用户名登录,然后选择要加入的房间。此外,可以将消息发送到服务器,并将收到的消息正确打印到屏幕上。这都是基于文本的。

在客户端程序中,有一个主线程,允许用户按下字符,然后将其推送到向量上;它看起来像这样:

    std::vector<char> current_message;/*global*/
    while(1)
    {
      c = '\0';
      while(c != '\n')/*Break when enter is pressed(send message)*/
      {       
         c = my_getch();
         if((c == '\n' && current_message.size() == 0)/*Cannot send blank messages*/
             || (c == 127 && char_count == 0))
         {
            c = '\0';
            continue;
         }

         if(!my_isarrow(c))
         {
            if(c != 127)
               char_count++;
            else char_count--;
            printf("%c", c);
            current_message.push_back(c);
         }
         if(current_message.size() == 250)/*Send the message if close to buf size*/
            c = '\n';

      }
      send_message(current_message, server);
      current_message.clear();/*remove characters from already-sent buffer*/
   }

还有一个线程过程从服务器检索消息这个过程是必需的,因为我们需要允许客户端同时发送消息,同时他正在等待来自服务器的消息。

该过程如下所示:

void *get_messages(void *data)
{
   pthread_detach(pthread_self());/*detach the thread*/
   int *sock = (int *) data;/*the thread data passed in is actually a socket
                             which we use to retrieve messages from server*/
   while(1)
   {
      packet_t pkt;
      read(*sock, &pkt, sizeof(packet_t));/*block until a message is received*/
      for(int i = 0; i < strlen(pkt.user_name); i++)
      {
         if(pkt.user_name[i] == '\n')
            pkt.user_name[i] = '\0';
      }
      pthread_mutex_lock(&lock);

      chat_buffer.push_back(pkt);

      for(int i = 0; i < 50; i++)
         printf("\n");/*emulate clearing of terminal window*/

      for(int i = 0; i < chat_buffer.size(); i++)/*chat_buffer is a global vector*/
                                                 /*that contains all received messages*/
      {
         for(int j = 0; j < strlen(chat_buffer[i].msg); j++)
         {
            if(chat_buffer[i].msg[j] == '\n')/*remove newlines(inefficient)*/
               chat_buffer[i].msg[j] = '\0';
         }
          /*print out all received messages to the client terminal*/
         printf("%s: %s\n", chat_buffer[i].user_name, chat_buffer[i].msg);

      }
      printf("----------------------------------------------------\n");/*some formatting for readability*/
      for(int i = 0; i < current_message.size(); i++)
         printf("%c", current_message[i]);    *******This is the problem area*******
}

当一个客户(我)输入了一些字母并将它们推送到缓冲区时,程序中的问题就会出现。并且,与此同时,我们收到了来自服务器的消息,并且屏幕正在“刷新”。您可以看到 get_messages(void *) 过程中发生了什么。但是,当发生此屏幕刷新时,我不希望我(我)客户已经输入的字母消失;为了解决这个问题,我添加了一行代码,它打印出当前在我的 current_message 向量中的所有字母。但是,字母并没有打印出来(即使这里的代码清楚地说明它们应该打印出来) 注意:在我按下键盘上的某个键后,缓冲区中的字符就会显示出来。

我的 getch() 函数的代码如下所示:

int my_getch()/*This actually didn't come from my brain*/
{
    struct termios oldt, newt;
    int ch;
    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    ch = getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    return ch;
}

此外,my_isarrow 函数只是解析传入的字符以查看它是否是箭头键。我想忽略箭头键,因为它会上下移动光标(我不想要这个。)

那么,有没有人遇到过这个问题,或者任何人都可以在这里看到他们已经处理过的问题?

问候,威廉。

4

1 回答 1

2

问题就在那里,因为 stdout 是一个缓冲流。

您需要在 for 循环之后放置一个 fflush(stdout) ;

另一个 fputc(current_message[i], stdout) 而不是 printf("%c", current_message[i]) 因为这样更有效:

这是您需要的增量:

  printf("----------------------------------------------------\n");/*some formatting for readability*/
  for(int i = 0; i < current_message.size(); i++) {
     fputc(current_message[i], stdout);    
  }
  fflush(stdout); /* make sure that stdout is flushed, as stdout is buffered */
于 2013-05-09T23:21:13.910 回答