2016-05-14 15 views
2

writev()/ readv()で作成されたクライアントとサーバーの通信に問題があります。readvでソケットからデータを読み取る

私は2つの構造体、headerdataは次のように定義されています

typedef struct { 
    int op; 
    int key; 
} message_hdr_t; 
typedef struct { 
    int len; 
    char *data; 
} message_data_t; 

サーバは(短期的に)ない:(ショートで)

message_hdr_t h = {1, 11}; 
message_data_t d; 
d.len = 3; 
strcpy(d.data, "msg"); 

struct iovec tosend[2]; 
tosend[0].iov_base = &h; 
tosend[0].iov_len = sizeof(message_hdr_t); 
tosend[1].iov_base = &d; 
tosend[1].iov_len = sizeof(message_data_t); 

writev(socket, tosend, 2); 
close(socket); 

クライアント:

struct iovec received[2]; 
readv(socket, received, 2); 
message_hdr_t header; 
header.op = ((message_hdr_t *) received[0].iov_base)->op; 
header.key = ((message_hdr_t *) received[0].iov_base)->key; 
printf("Received op: %i, key: %i\n",header.op,header.key; 
close(socket); 

received[0].iov_baseがなのでクライアントはセグメンテーションを取得します。どうして? ソケットが正しく開かれ、クライアントがサーバーに正しく接続されています。これはAF_UNIXソケットです。

+0

'struct iovec'とは何ですか? – alk

+2

@alk標準のPOSIX構造です。 –

答えて

1

まず、サーバーコードでは、ポインタと書いています。これは意味がありません。ワイヤを介してポインタを送信する必要はありません。

char* message = ...; 
message_hdr_t h = {1, 11}; 

uint32_t message_length = strlen(message); 

struct iovec tosend[3]; 

tosend[0].iov_base = &h; 
tosend[0].iov_len = sizeof(message_hdr_t); 

tosend[1].iov_base = &message_length; 
tosend[1].iov_len = sizeof(message_length); 

tosend[2].iov_base = message; 
tosend[2].iov_len = message_length; 

(あなたがメッセージヘッダに文字列の長さを移動し、ベクトルの一つの要素を保存したい、とプロトコルが読みやすくなる場合があります):文字列を送信するには、このような何かをしなければなりません。

第2に、readvは、メモリを割り当てたり、読み込むバイト数を指定したりしません。 readvに渡されたIOベクトル内のiov_baseiov_lenを正しく初期化するのはあなたの仕事です。動的に割り当てられた可変長文字列を読み込むには、おそらく2度読みたいと思うでしょう。最初に、文字列の長さを含むメッセージの一部を読み取り、文字列を割り当てて残りのメッセージを読み取ります。

+0

ありがとう、シンプルで明確な答え。 –