gpt4 book ai didi

c - 如何准备 UDP 数据报发送到服务器

转载 作者:行者123 更新时间:2023-11-30 18:15:22 26 4
gpt4 key购买 nike

我必须编写一个程序,将文件从 UDP 客户端发送到 UDP 服务器。

我通过这种连接发送数据没有任何问题,但不同的问题是处理我们的协议(protocol)规范。也许有人可以帮助我理解如何正确实现这些步骤:

第 1 步:

发送第一个包:数据数组的第一个元素,类型规范的 int 值。

之后文件名大小(不带路径)为无符号短

之后文件名(不带路径)为 C 字符串,不带 NULL 终止符。

至少文件长度应该是无符号整数

两种大小都应按网络字节顺序发送!

所有这些信息都必须位于一个单个数据报中。所以实际上我只有一个由客户端发送的 unsigned char 数组。

我以为我可以将任何东西一个接一个地分配给这个数组。但不要认为这有效。

第 2 步:

发送第二个包:类型规范为 int 作为第一个元素。然后是给定文件的数据(我也将其保存为 unsigned char 数组)。这要容易得多,因为我只拥有可以轻松放入我的 unsigned char 数组中的信息。

所以,我认为,必须有一种方法来构建一个通用方法或类似的方法,它返回一个数据报,这样我就可以填写我想要在此数据报中包含的所有数据类型,并准备好发送我的数据报, 你知道?

如果有人知道我如何以正确的方式“准备”数据报,那就太好了 - 对我来说最重要的是:

我的数据报数组应该具有哪种类型?要使用 sendTo() 发送它,它需要是一个 unsigned char 数组,对吗?

最诚挚的问候,非常感谢!

最佳答案

您可以使用结构来映射您的信息,例如:

struct Packet {
unsigned short filnemanesize;
char [MAX_LEN] filename;
unsigned int filesize;
//etc.
}

可以直接通过套接字发送该结构

send(mySocket, (void*) myStruct, sizeof(myStuct), 0);

但是编译器使用不同的成员包装,因此服务器会看到不同的数据。 (对于完全相同的平台/编译器来说是安全的)。

常见的做法是将结构序列化为 char 数组,这是一个完整的示例:

#include <stdint.h>
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib, "Ws2_32.lib")
using namespace std;


#define MAX_FILENAME_SIZE 10
typedef struct {
int32_t type;
uint16_t fileNameSize;
uint32_t extraPadding; //just some manual padding (example)
char fileName [MAX_FILENAME_SIZE];
uint32_t fileSize;
} Packet;

const size_t PACKET_RAW_SIZE = sizeof(int32_t) + sizeof(uint16_t) + (MAX_FILENAME_SIZE * sizeof(char)) + sizeof(uint32_t);

size_t serialize(unsigned char * const dst, const Packet * src) {

/* Protocoll Specification:
[Type:4Byte][fileNameSize:2Byte][fileName:nByte][fileSize:4Byte]
*/


uint16_t offset = 0;

//type
memcpy(dst + offset, &src->type, sizeof(src->type));
offset += sizeof(src->type);

//fileNameSize
memcpy(dst + offset, &src->fileNameSize, sizeof(src->fileNameSize));
offset += sizeof(src->fileNameSize);

//fileName
memcpy(dst + offset, &src->fileName, ntohs(src->fileNameSize));
offset += ntohs(src->fileNameSize);

//fileSize
memcpy(dst + offset, &src->fileSize, sizeof(src->fileSize));
offset += sizeof(src->fileSize);

return offset;
}

int main(int argc, _TCHAR* argv[])
{
unsigned char buffer[PACKET_RAW_SIZE];
for (int i = 0; i < PACKET_RAW_SIZE; buffer[i++] = 0); //nice visual effect, not nessasarry
Packet myPacket;
myPacket.type = htonl(0xAFFEAFFE);
myPacket.fileNameSize = htons(4); //convert 4 to network byte order as required
myPacket.fileSize = htonl(42);
myPacket.fileName[0] = 'T';
myPacket.fileName[1] = 'E';
myPacket.fileName[2] = 'S';
myPacket.fileName[3] = 'T';

myPacket.extraPadding = 0xFFFFFFFF; // better visual effect

cout << "struct Packet size: " << sizeof(Packet) << endl;
cout << "PACKET_RAW_SIZE: " << PACKET_RAW_SIZE << endl;

size_t bufferSize = serialize(&buffer[0], &myPacket);

cout << "myPacket: " << endl;
for (int i = 0; i < sizeof(myPacket); i++) {
unsigned char * ptr = (unsigned char *) &myPacket;
cout << std::showbase << std::hex << "Offset: " << i * sizeof(unsigned char) << "\t Value: " << (uint16_t)*(ptr + i) << "\t" << *(ptr + i) << endl;
}
cout << endl;

cout << "buffer: " << endl;
for (int i = 0; i < bufferSize; i++) {
cout << std::showbase << std::hex << "Offset: " << i * sizeof(unsigned char) << "\t Value: " << (uint16_t)buffer[i] << "\t" << buffer[i] << endl;
}

cout << endl;

return 0;
}

/*
Program-Output:

struct Packet size : 28
PACKET_RAW_SIZE : 20
myPacket :
Offset : 0 Value : 0xaf »
Offset : 0x1 Value : 0xfe ■
Offset : 0x2 Value : 0xaf »
Offset : 0x3 Value : 0xfe ■
Offset : 0x4 Value : 0
Offset : 0x5 Value : 0x4 ♦
Offset : 0x6 Value : 0x9a Ü
Offset : 0x7 Value : 0xf ☼
Offset : 0x8 Value : 0xff
Offset : 0x9 Value : 0xff
Offset : 0xa Value : 0xff
Offset : 0xb Value : 0xff
Offset : 0xc Value : 0x54 T
Offset : 0xd Value : 0x45 E
Offset : 0xe Value : 0x53 S
Offset : 0xf Value : 0x54 T
Offset : 0x10 Value : 0x52 R
Offset : 0x11 Value : 0x17 ↨
Offset : 0x12 Value : 0x9f ƒ
Offset : 0x13 Value : 0xf ☼
Offset : 0x14 Value : 0x1 ☺
Offset : 0x15 Value : 0
Offset : 0x16 Value : 0
Offset : 0x17 Value : 0
Offset : 0x18 Value : 0
Offset : 0x19 Value : 0
Offset : 0x1a Value : 0
Offset : 0x1b Value : 0x2a *

buffer :
Offset : 0 Value : 0xaf » | <= type
Offset : 0x1 Value : 0xfe ■ |
Offset : 0x2 Value : 0xaf » |
Offset : 0x3 Value : 0xfe ■ |
Offset : 0x4 Value : 0 | <= fileNameSize
Offset : 0x5 Value : 0x4 ♦ | (network byte order)
Offset : 0x6 Value : 0x54 T | <= fileName
Offset : 0x7 Value : 0x45 E |
Offset : 0x8 Value : 0x53 S |
Offset : 0x9 Value : 0x54 T |
Offset : 0xa Value : 0 | <= fileSize
Offset : 0xb Value : 0 | (network byte order)
Offset : 0xc Value : 0 |
Offset : 0xd Value : 0x2a |

*/

可以看到,缓冲区只包含所需的数据。并且映射是按照规范中的要求进行的。所有手动和编译器填充都不在缓冲区内。htons/htonl 用于字节顺序转换。

更好的是某种文本序列化,例如 xml 或 json(恕我直言)

关于c - 如何准备 UDP 数据报发送到服务器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30501561/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com