Sending a struct with char pointer inside?
im trying to send a packet from my C program to my Delphi program, the data is variable in size, and if i used char Data[1024]; i开发者_如何学运维t will send 1024 bytes even if the data is 3 bytes, and if the data is larger than 1024 it wont send all of it :(
struct Packet
{
int State_;
char *Data;
};
struct Packet MyPacket;
MyPacket.Data = (char *) calloc(8, sizeof(char));
memcpy(MyPacket.Data, "thi sis", 8);
send(Socket, MyPacket, (int)sizeof(struct Packet), 0);
thanks oh, btw, im using gcc under windows
An old trick for encapsulating the packet in a single block is to use an array of length 1 at the end of the Packet.
struct Packet
{
unsigned packetLengthInBytes_;
/* All the fixed fields in the packet */
int State_;
/* Generic data in the packet - of actual length given by packetDataLength(packet) */
char Data[1];
};
unsigned packetDataLength(Packet* packet)
{
return packet->packetLengthInBytes_ - (sizeof(Packet) - 1);
}
Packet* createPacketFromData(const char* data, unsigned dataSize)
{
unsigned packetSize = sizeof(Packet) + dataSize - 1;
Packet* packet = (Packet*)malloc(packetSize);
packet->packetLengthInBytes_ = packetSize;
memcpy(packet->Data, data, dataSize);
return packet;
}
int sendData(int sock, const char* data, unsigned dataSize)
{
Packet* packet = createPacketFromData(data, dataSize);
/* [ Yes, think about endian issues.] */
send(sock, packet, packet->packetLengthInBytes_, 0);
free(packet);
}
Note how this means we have a single send() call, and in general can pass a Packet around as a single object, with one allocation call and one deallocation call.
You should implement a serialization method for your struct. The way you are trying to send it now is never going to work since you are not actually sending the contents of your char*, you are sending the pointer itself. That is only an internal address and the receiving program will have no idea what you are trying to accomplish.
A pointer is a reference to a memory address, so you are currently sending the address instead of the content. Thus you need to change it to send an array of actual characters.
You need to send either the size information (prefered) before the actual array of chars or define an end of character array sign
Your code is incorrect -- when you send the structure directly like that, what you're sending is a pointer (address of Data_
), not the actual string. You have two choices:
As you already mentioned, use a fixed-size array inside the structure.
Manually send the length followed by the actual string data over the socket, for example:
int length = 8;
char *data = (char *) calloc(length, sizeof(char));
memcpy(data, "thi sis", 8);
send(Socket, &length, sizeof(length), 0);
send(Socket, data, length, 0);
The receiving side (Delphi) should be made aware of the size of the data by a method agreed upon by the sender and the receiver (i.e, you should implement a simple protocol for data transfer). As you are transferring an entire struct
, your protocol should also take care of specifying types. The easiest solution is to use a textual data interchange format like XML or JASON:
// Code to demonstrate the idea, may not compile.
struct Packet MyPacket;
MyPacket.State_ = 0;
MyPacket.Data = (char *) calloc(8, sizeof(char));
memcpy(MyPacket.Data, "thi sis", 8);
const char* packetXml = PacketToXml();
/*
packetXml =
<Packet>
<State>0</State>
<Data>thi sis</Data>
</Packet>
*/
size_t len = strlen(packetXml);
send(Socket, (char*)&len, sizeof(size_t), 0);
send(Socket, packetXml, len, 0);
Really, what you want to do is send a short header for your message followed by the variable-length data. The header should contain at least the size of the data that follows it. A simple implementation goes something like this:
struct Packet {
int State_;
char *Data;
};
struct PacketHeader {
uint32_t state;
uint32_t len;
};
int send_packet(int sock, struct Packet *pkt)
{
struct PacketHeader hdr;
int len = strlen(pkt->Data); /* If Data is a C string */
hdr.state = htonl(pkt->State_);
hdr.len = htonl(len);
send(sock, &hdr, sizeof(hdr), 0);
send(sock, pkt->data, len, 0);
}
I don't know Delphi, but to parse the packet, you do the opposite. Read the header to get the size of the data, then read that much data out of the socket into a newly-allocated buffer.
You need to specify the correct length of the data sent. Using:
sizeof(struct Packet)
as you have done is wrong and will only give you 8 bytes, 4 bytes for the int and 4 bytes for the char*, on a 32 bit system.
Note that
char*
is a different type from a character array. It's a pointer to a char. For example, the results of sizeof here are different:
char arr[1024];
char* pc = arr;
printf("%d, %d", sizeof(pc), sizeof(arr));
精彩评论