使用 readv 从 socket 读取数据
Reading data from socket with readv
我在使用 writev()/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);
但是客户端出现段错误,因为 received[0].iov_base
是 NULL
。为什么?
套接字已正确打开,客户端已正确连接到服务器。这是一个 AF_UNIX 插座。
首先,在您的服务器代码中,您正在编写一个指针。这是没有意义的。您不想通过线路传输指针。要传输字符串,您必须执行以下操作:
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_base
和 iov_len
是你的工作。为了读取动态分配的可变大小字符串,您可能需要读取两次。首先读取消息中包含字符串长度的部分,然后分配字符串,读取消息的其余部分。
我在使用 writev()/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);
但是客户端出现段错误,因为 received[0].iov_base
是 NULL
。为什么?
套接字已正确打开,客户端已正确连接到服务器。这是一个 AF_UNIX 插座。
首先,在您的服务器代码中,您正在编写一个指针。这是没有意义的。您不想通过线路传输指针。要传输字符串,您必须执行以下操作:
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_base
和 iov_len
是你的工作。为了读取动态分配的可变大小字符串,您可能需要读取两次。首先读取消息中包含字符串长度的部分,然后分配字符串,读取消息的其余部分。