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*******
}

プログラムの問題は、1 人のクライアント (私) がいくつかの文字を入力し、それらがバッファーにプッシュされたときに発生します。同時に、サーバーからメッセージが届き、画面が「更新」されました。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) を配置する必要があります。

printf("%c", current_message[i]) の代わりに fputc(current_message[i], stdout) を使用すると、少し効率的になります。

必要なデルタは次のとおりです。

  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 に答える