2016-05-14 2 views
2

У меня проблемы с обменом клиент-сервер, выполненные с помощью writev()/readv().Чтение данных из сокета с readv

Я две структуры, header и data определяются следующим образом:

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); 

Но клиент получает segfault, потому что received[0].iov_base is NULL. Зачем? Сокет правильно открыт и клиент правильно подключен к серверу. Это сокет 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 не выделяет для вас память или не объясняет, сколько байтов вы хотите прочитать. Это ваша задача правильно инициализировать iov_base и iov_len в векторе ввода-вывода, переданном readv. Чтобы прочитать динамически распределенную строку с переменным размером, вы, вероятно, захотите прочитать дважды. Сначала прочитайте часть сообщения, которое содержит длину строки, затем выделите строку и прочитайте остальную часть сообщения.

+0

Спасибо, простой и понятный ответ. –

Смежные вопросы