Bạn cần những điều sau đây để portably gửi struct của qua mạng:
Gói cấu trúc. Đối với trình biên dịch gcc và tương thích, hãy thực hiện việc này với __attribute__((packed))
.
Không sử dụng bất kỳ thành viên nào khác với số nguyên không có kích thước cố định, các cấu trúc đóng gói khác đáp ứng các yêu cầu này hoặc các mảng của bất kỳ yếu tố nào trước đây. Các số nguyên đã ký cũng OK, trừ khi máy của bạn không sử dụng biểu diễn bổ sung của hai.
Quyết định xem giao thức của bạn có sử dụng mã hóa số nguyên nhỏ hoặc lớn hay không. Thực hiện chuyển đổi khi đọc và ghi các số nguyên đó.
Ngoài ra, không lấy con trỏ của các thành viên của cấu trúc đóng gói, ngoại trừ những người có kích thước 1 hoặc các cấu trúc đóng gói lồng nhau khác. Xem this answer.
Ví dụ đơn giản về mã hóa và giải mã sau.Nó giả định rằng các hàm chuyển đổi thứ tự byte là hton8()
, ntoh8()
, hton32()
và ntoh32()
có sẵn (hai giá trị trước là không có op, nhưng ở đó có tính nhất quán).
#include <stdint.h>
#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
// get byte order conversion functions
#include "byteorder.h"
struct packet {
uint8_t x;
uint32_t y;
} __attribute__((packed));
static void decode_packet (uint8_t *recv_data, size_t recv_len)
{
// check size
if (recv_len < sizeof(struct packet)) {
fprintf(stderr, "received too little!");
return;
}
// make pointer
struct packet *recv_packet = (struct packet *)recv_data;
// fix byte order
uint8_t x = ntoh8(recv_packet->x);
uint32_t y = ntoh32(recv_packet->y);
printf("Decoded: x=%"PRIu8" y=%"PRIu32"\n", x, y);
}
int main (int argc, char *argv[])
{
// build packet
struct packet p;
p.x = hton8(17);
p.y = hton32(2924);
// send packet over link....
// on the other end, get some data (recv_data, recv_len) to decode:
uint8_t *recv_data = (uint8_t *)&p;
size_t recv_len = sizeof(p);
// now decode
decode_packet(recv_data, recv_len);
return 0;
}
Theo như chức năng chuyển đổi thứ tự byte được quan tâm, hệ thống của bạn htons()
/ntohs()
và htonl()
/ntohl()
có thể được sử dụng, ví số nguyên 16- và 32-bit, tương ứng, chuyển đổi sang/từ lớn về cuối nhỏ. Tuy nhiên, tôi không biết về bất kỳ chức năng tiêu chuẩn nào cho các số nguyên 64 bit, hoặc để chuyển đổi thành/từ nhỏ endian. Bạn có thể sử dụng my byte order conversion functions; nếu bạn làm như vậy, bạn phải thông báo cho nó thứ tự byte của đơn đặt hàng của máy bằng cách xác định BADVPN_LITTLE_ENDIAN
hoặc BADVPN_BIG_ENDIAN
. Đối với các số nguyên đã ký, các hàm chuyển đổi có thể được thực hiện một cách an toàn giống như cách tôi đã viết và liên kết (hoán đổi byte trực tiếp); chỉ cần thay đổi unsigned để ký.
CẬP NHẬT: nếu bạn muốn một giao thức nhị phân hiệu quả, nhưng không thích loay hoay với các byte, bạn có thể thử một cái gì đó giống như Protocol Buffers (C implementation). Điều này cho phép bạn mô tả định dạng thư của mình trong các tệp riêng biệt và tạo mã nguồn mà bạn sử dụng để mã hóa và giải mã thư của định dạng bạn chỉ định. Tôi cũng thực hiện một cái gì đó tương tự bản thân mình, nhưng rất đơn giản; xem my BProto generator và some examples (xem tệp .bproto và addr.h để biết ví dụ về cách sử dụng).
Nguồn
2011-11-03 20:16:58
Tôi sẽ thử phương pháp này, tôi chỉ muốn hỏi nếu tôi chỉ sử dụng sprintf và ghi tất cả dữ liệu vào chuỗi bằng dấu tách để tách các phần tử của cấu trúc và gửi qua socket và sau đó sử dụng strtok để trích xuất từng phần tử mặt khác ? Đây có phải là một giải pháp khả thi không? – user434885
có, sprintf sẽ hoạt động, nhưng * chỉ * cho số nguyên; nếu bạn muốn gửi một chuỗi (tức là mảng byte nguyên), bằng cách sử dụng phương thức này, bạn sẽ phải coi chúng như là một mảng các byte và chuyển đổi từng byte thành một số nguyên, chèn khoảng trắng vào giữa. Ví dụ: "abc" sẽ được gửi dưới dạng "97 98 99". Điều này có thể thích hợp hơn vì nó dễ phân tích hơn khi gỡ lỗi, nhưng nó rất vụng về để mã hóa/giải mã, đặc biệt nếu bạn muốn kiểm tra lỗi đầy đủ khi giải mã. –
Động lực đằng sau điểm đạn thứ hai của bạn - chỉ sử dụng số nguyên không dấu. Tại sao các ký tự không thể được sử dụng trong cấu trúc (hoặc mảng char) để gửi các chữ cái, byte hoặc chuỗi? – aaronsnoswell