[英]C struct with data arrays over a socket
用 C 编程应用程序,我有以下struct
数据,我想通过网络套接字将其发送到另一个进程。 我的结构定义如下所示:
typedef struct __attribute__((__packed__)) Matrix {
uint32_t rows;
uint32_t cols;
char * matrix;
} matrix_s;
typedef struct __attribute__((__packed__)) RequestPacket {
uint32_t request_code;
matrix_s * mat;
} request_packet_s;
我想使用send
/ write
通过网络发送RequestPacket
,但我不确定如何处理数组指针。 如果我使用的结构的静态数组就没有问题,但它需要是动态的,因为我不知道rows
和cols
的时间提前。 此外,指针不能被其他进程解释,所以我需要通过套接字发送原始数据。
我已经将__packed__
属性添加到这些结构定义中,以尝试消除填充。 太好了,但是如果我需要在发送之前将所有数据倒入线性缓冲区,那有什么意义呢?
我问这个问题是因为我想知道通过网络发送这些数据的最佳方法。 在此先感谢您的帮助。
性能良好的代码应该尽量减少副本。 下面的方法在用户代码中不执行任何复制,它不会重写数据,并且它可以适用于从网卡直接到应用程序内存的零复制路径。
这两个结构体,以及字符数组,构成了一棵树。 对象是树节点,指向对象的指针是树边。
要传输树,您需要按某种顺序遍历它。 是广度优先还是深度优先还是其他顺序取决于您 - 只要发射器和接收器都同意该顺序。
按遍历顺序发送结构,不做任何更改。 接收器忽略指针,并利用遍历顺序将指针重写为接收端的正确位置。
例如 - 假设阻塞代码,并编写了safe_write
来正确处理信号(大多数使用没有包装器的裸write
代码做错了 - 众所周知,POSIX API 很难正确使用;它们让你自满,因为它们似乎可以工作- 直到他们不会)。
让我们也决定我们的 API 将正确处理 NULL 指针 - 它会跳过 NULL 指针,如果接收到 NULL 指针,接收器将不会期望发送任何内容。
您尚未解决的问题是版本控制:实际上,您定义的大多数对象都没有大小,因此将来无法扩展它们。 这可以通过向每个结构添加显式长度字段来解决,以便接收器可以正确地将它们成帧。 它会简单地忽略附加字段。
结构定义可以在 32 位和 64 位平台之间移植。
typedef unsigned char BOOL;
enum { FALSE, TRUE };
#define PTR(type, name) union { type *name; uint64_t name##_; }
#define MAX_MATRIX_SIZE 128*128
typedef struct __attribute__((__packed__)) Matrix {
uint32_t rows;
uint32_t cols;
PTR(char, matrix);
} matrix_s;
typedef struct __attribute__((__packed__)) RequestPacket {
uint32_t request_code;
PTR(matrix_s, mat);
PTR(matrix_s, opt_kernel);
} request_packet_s;
#undef PTR
BOOL safe_write(int fd, void *buf, size_t length) {
// Returns TRUE if buf is NULL or if writing had succeeded, FALSE on error
if (!buf) return TRUE;
assert(length);
// TODO
return FALSE;
}
BOOL sendBytes(int fd, char *bytes, size_t length) {
if (!bytes) return TRUE;
assert(length); // Sending a non-NULL pointer for a zero-sized block
// we shall declare to be a protocol error. Since
// this is the send side, this is a bug.
return safe_write(fd, bytes, length);
}
BOOL sendMatrix(int fd, matrix_s *mat) {
if (!mat) return TRUE;
if (!safe_write(fd, mat, sizeof(*mat))) return FALSE;
return sendBytes(fd, mat->matrix, mat->rows * mat->cols);
}
BOOL sendRequestPacket(int fd, request_packet_s *req) {
if (!req) return TRUE;
if (!safe_write(fd, req, sizeof(*req))) return FALSE;
if (!sendMatrix(fd, req->mat)) return FALSE;
return sendMatrix(fd, req->opt_kernel);
}
BOOL safe_read(int fd, void *buf, size_t length) {
// Returns TRUE if reading had succeeded, FALSE on error
if (!buf) return TRUE;
if (!length) return FALSE; // Protocol error on receive: this is a
// data validation failure, and must be handled
// like any other error.
// TODO
return FALSE;
}
static inline BOOL free_read(void **const ptr) {
free(*ptr);
*ptr = NULL;
return FALSE;
}
BOOL malloc_read(int fd, void **const buf, size_t length) {
// This should be using an arena allocator, really.
if (!*buf) return TRUE;
if (!length) return FALSE;
*buf = malloc(length);
if (!*buf) return FALSE;
if (!safe_read(fd, *buf, length)) return free_read(buf);
return TRUE;
}
BOOL recvMatrix(int fd, matrix_s **const mat) {
if (!malloc_read(fd, mat, sizeof(**mat))) return FALSE;
size_t size = (*mat)->rows * (*mat)->cols;
if (size > MAX_MATRIX_SIZE) goto error;
if (size)
if (!malloc_read(fd, &(*mat)->matrix, size)) goto error;
return TRUE;
error:
return free_read(mat);
}
BOOL recvRequestPacket(int fd, request_packet_s **const req) {
if (!malloc_read(fd, req, sizeof(**req))) return FALSE;
if (!recvMatrix(fd, &(*req)->mat)) goto error1;
if (!recvMatrix(fd, &(*req)->opt_kernel)) goto error2;
return TRUE;
error2:
free_read(&(*req)->mat);
error1:
return free_read(req);
}
typedef struct __attribute__((__packed__)) Matrix {
uint32_t rows;
uint32_t cols;
char matrix[];
} matrix_s;
typedef struct __attribute__((__packed__)) RequestPacket {
uint32_t request_code;
matrix_s mat;
} request_packet_s;
request_packet_s *allocreq(uint32_t req, size_t rows. size_t cols);
{
request_packet_s *p = malloc(sizeof(*p) + rows * cols);
/* init it - d osomething */
return p;
}
然后你可以在一个电话中发送/写入
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.