2016-10-31 3 views
1

私はソケットを使ってCのクライアント/サーバコマンドラインチャットプログラムで作業しています。 1つの問題を除いて、すべてがうまく機能しています。クライアントが無効なコマンドをサーバーに送信すると、アプリケーションの使用方法を知らせるためにコマンドリストを返送しようとしています。私は複数の連続した "送信"を実行してこれを実行しようとしていましたが、クライアントは最初のメッセージのみを取得します。私はいくつかの同様の質問(主にJavaソケット用)を見つけましたが、これを理解するのに役立つ答えはありませんでした。C - ソケットチャットルーム - クライアントが連続したメッセージを受信

コードと出力

サーバーサイドコード:(別のスレッドループ内)

void message_self(char *msg, client_t *client) { 
    send(client->sd, msg, strlen(msg) + 1, 0); 
} 

void commands(client_t *client) { 
    message_self("Commands:\n", client); 
    message_self("\tUser Login:\tlogin <username> <password\n", client); 
    message_self("\tCreate User:\tnewuser <username> <password>\n", client); 
    message_self("\tList Users:\twho\n", client); 
    message_self("\tMessaging:\tsend all|<username> <message>\n", client); 
    message_self("\tQuit Chat:\tlogout\n", client); 
} 

クライアント側:

if((len = recv(sd, buff_in, sizeof(buff_in), 0)) > 0) { 
    fputs(buff_in, stdout); 
} 

出力:空白行がちょうど入る当たっユーザーですサーバーはコマンド(クライアント)を呼び出します。 1行だけを受信した後、ユーザは「send」を入力し、対応するエラーメッセージをサーバから受信する。

Connected. Chat Room Version 2 

Commands: 
send 
Server: Denied. Please log in. 

私は各message_selfの間ではusleep(50)を置く場合は、私が期待される出力を得る:

Connected. Chat Room Version 2 

Commands: 
    User Login:  login <username> <password> 
    Create User: newuser <username> <password> 
    List Users:  who 
    Messaging:  send all|<username> <message> 
    Quit Chat:  logout 

私はちょうど良い方法がなければならない考え出し。私はまた、すべての書式設定文字で1つのバッファにリスト全体を連結しようとしましたが、それは依然として "コマンド:"を印刷した後にクライアント側で断ち切ります。誰かがこれをサーバー側のクライアント側から解決する方法を知っていれば、感謝しています。

+1

送信、あなたはそれぞれの行の後に終端 ' '\ 0''が含まれます。受信側では、 'fputs'は最初の '\ 0'まで、つまり1行だけを出力します。すべての行が1つのパケットで送信される理由は、おそらく[Nagleのアルゴリズム](https://en.wikipedia.org/wiki/Nagle%27s_algorithm)です。通常、ネットワークを介して受信したデータのヌル終端に頼ってはならず、代わりに最初にデータの長さを送信します。 –

+0

バッファーが十分な大きさであれば、コマンドリスト全体を1つのメッセージで送信することを検討できます。 –

+0

@ KarstenKoop - これは理にかなっています。クライアント側で簡単に分割することができます。 – sylisphoenix

答えて

0

@ KarstenKoopがコメントしたように、ヌルターミネーターをサーバーから送信すると、すべてがねじ込まれます。代わりに、strlenバイトを送信し、クライアント側でlenを使用してfputsのメッセージを終了してください。

サーバー:

send(client->sd, msg, strlen(msg), 0); 

クライアント:

if((len = recv(sd, buff_in, sizeof(buff_in), 0)) > 0) { 
    buff_in[len] = '\0'; 
    fputs(buff_in, stdout); 
} 
関連する問題