发送带有char指针的结构?

时间:2010-12-13 05:22:08

标签: c sockets gcc winsock

我尝试从我的C程序向我的Delphi程序发送数据包,数据大小可变,如果我使用char数据[1024];即使数据是3个字节,它也会发送1024个字节,如果数据大于1024,它将不会发送所有数据:(

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

感谢 哦,顺便说一下,我在windows下使用gcc

7 个答案:

答案 0 :(得分:5)

您应该为您的struct实现序列化方法。 您现在尝试发送它的方式永远不会起作用,因为您实际上并未发送char *的内容,而是您自己发送指针。这只是一个内部地址,接收程序将不知道你想要完成什么。

答案 1 :(得分:5)

将数据包封装在单个块中的一个老技巧是在数据包末尾使用长度为1的数组。

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

注意这意味着我们有一个send()调用,并且通常可以将一个Packet作为单个对象传递,只有一个分配调用和一个释放调用。

答案 2 :(得分:1)

接收方(Delphi)应通过发送方和接收方商定的方法了解数据的大小(即,您应该实现一个简单的数据传输协议)。当您传输整个struct时,您的协议也应该注意指定类型。最简单的解决方案是使用XML或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);

答案 3 :(得分:1)

指针是对内存地址的引用,因此您当前正在发送地址而不是内容。因此,您需要更改它以发送一组实际字符 您需要在实际的字符数组之前发送大小信息(首选)或定义字符数组符号的结尾

答案 4 :(得分:1)

您的代码不正确 - 当您直接发送结构时,您发送的是指针(Data_的地址),而不是实际的字符串。你有两个选择:

  1. 正如您已经提到的,在结构中使用固定大小的数组。

  2. 手动发送长度,然后通过套接字发送实际字符串数据,例如:


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

答案 5 :(得分:1)

实际上,您要做的是为您的消息发送一个短标题,然后是可变长度数据。标头应至少包含其后面的数据大小。一个简单的实现是这样的:

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

我不知道Delphi,但要解析数据包,你会反其道而行之。读取标头以获取数据的大小,然后从套接字中读取那么多数据到新分配的缓冲区中。

答案 6 :(得分:0)

您需要指定发送数据的正确长度。使用:

sizeof(struct Packet)

正如你所做的那样是错误的,在32位系统上只给你8个字节,4个字节用于int和4个字节用于char *。

请注意

char*

是与字符数组不同的类型。它是一个指向char的指针。例如,sizeof的结果不同:

char arr[1024];
char* pc = arr;
printf("%d, %d", sizeof(pc), sizeof(arr));