2016-05-14 108 views
2

我在使用writev()/ readv()進行客戶端 - 服務器通信時遇到問題。從readv讀取數據

我有兩個結構,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_baseNULL。爲什麼? 套接字已正確打開並且客戶端已正確連接到服務器。這是一個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; 

(您可能要字符串長度移至消息頭和保存向量的一個元素,使協議更具可讀性)。

其次,readv將不會爲您分配內存,或者您想要讀取多少字節。您的工作是在傳遞給readv的IO向量中正確初始化iov_baseiov_len。爲了讀取動態分配的可變長度字符串,您可能需要讀取兩次。首先,讀取包含字符串長度的消息的一部分,然後分配字符串,並閱讀消息的其餘部分。

+0

謝謝,簡單明瞭的答案。 –