如何创建我自己的数据包通过UDP发送?
我正在C中实现TFTP协议的自己的客户端 - 服务器应用程序。在阅读了TFTP的RFC并开发了一个简单的套接字客户机 - 服务器应用之后,现在我对如何创建必须为TFTP协议创建的特定数据包有点困惑。如何创建我自己的数据包通过UDP发送?
例如,WRQ分组必须是这样的:
2 bytes string 1 byte string 1 byte
------------------------------------------------
| Opcode | Filename | 0 | Mode | 0 |
------------------------------------------------
其从官方RFC萃取。
我有一个.h在其中我定义了数据包的所有结构,但我不知道我是否正确地做,我很幸运在网上找到信息。
我为此包创建的结构是:
struct WRQ {
signed short int opcode; //2 bytes
char * filename; // N bytes
char zero_0; // 1 byte
char * mode; // N Bytes
char zero_1; // 1 byte
};
我有两个疑惑:
一个)当我做出的sizeof(结构WRQ)它返回20个字节。这不是我想要的尺寸。为什么发生这种情况?
b)我该如何定义字符串?因为我希望服务器接收字符串本身,并且,我认为,这样,它将接收到客户机中字符串的指针。
我希望一切都很清楚,你可以帮助我,因为我现在被卡住了!
在你的代码中,char * filename;
是一个指向char的指针。这意味着filename
只占用4个字节。即使您的字符串长度为1000字节,由于filename
只是一个指针,它只包含字符串第一个字符的4字节内存地址。
因此,您有两种解决方案:使用char filename[MAX_LENGTH]
来声明一个大小为MAX_LENGTH
的字符串,并始终通过该字符串。或者,您可以包含另一个字段,例如“filename_length”,它告诉您读取文件名字段时需要多少字节。
(上面实际上是错误的,filename
可能不是4字节长,文件名将是sizeof(char*)
字节,这可能是4个字节,但指针并不总是4个字节,现在人们正在进入很多在64位体系结构上假设一个4字节指针的麻烦,所以我只是说'不要低估我。]
要回答你的第二个问题 - 为什么是sizeof()20字节?编译器会用额外的字节填充结构的各个部分,以便每个成员都可以放入一个4字节的边界内。编译器可以用“单词”而不是奇怪大小的结构高效地工作。 (同样,“4”取决于体系结构,每个体系结构都有自己的“单词”长度)。这就是所谓的对齐。有一个优秀的SO线程给出了更多的细节:Why isn't sizeof for a struct equal to the sum of sizeof of each member?
你不能只是把char*
放在那里,并期望它工作,因为这是一个指针,你需要实际的字符数据出现在数据包中(在两个程序之间传递的指针几乎不会工作!)。由于数据包的文件名部分是可变长度的,因此您无法将整个数据包表示为结构,因为您正在尝试执行此操作。相反,你应该动态地通过连接需求的作品,如具有此签名的函数生成的数据包:
vector<char> makePacket(uint16_t opcode, const char* filename, const char* mode);
我认为它不能表达这种方式,所以...我怎么能做到这一点?我从来没有使用C中的矢量
对不起,我说'vector
下面的代码(有没有错误检查)是建立在数据包的一个可能的方式并发送它。请注意,它假定filename
和mode
都不是NULL。我不知道这是否是一个有效的假设。即使是这样,在实际代码中使用它们之前检查NULL也是明智的:
struct WRQ *p;
int packetLen;
char *buf;
char *pos;
int ret;
// compute packet length. Start with fixed size data
packetLen = sizeof(p->opcode) + sizeof(p->zero_0) + sizeof(p->zero_1);
// This assumes (possibly incorrectly) that filename and mode are not null
packetLen += strlen(p->filename) + 1;
packetLen += strlen(p->mode) + 1;
// allocate the buffer
buf = malloc(packetLen);
pos = buf;
// and start filling it in
// I am assuming (but didn't study the RFC that it should be network byte order)
*(signed short int*)pos = htons(p->opcode);
pos += sizeof(p->opcode);
strcpy(pos, p->filename);
pos += strlen(p->filename) + 1;
*pos = p->zero_0;
strcpy(pos, p->mode);
pos += strlen(p->mode) + 1;
*pos = p->zero_1;
ret = send(s, buf, packetLen, flags);
free(buf);
我会试试这个!谢谢! – 2011-04-10 16:39:15
C结构不能具有可变大小。您必须将“文件名”和“模式”定义为char field_name [preset size];
或在运行时手动构建内存缓冲区中的结构。最后,如果你需要的是TF中的TFTP实现,你可以打赌,如果已经有人写了,你可以打赌。例如。在各种Linux发行版中使用了BSD'ed tftp-hpa。
我会尽量让它在char * buff变量中做,谢谢! – 2011-04-10 16:38:46
你可能会得到答案你的问题http://*.com/questions/5596428/sizeofstruct-returns-unexpected-value – Peacelyk 2011-04-10 15:21:24
问:如何字符串长度在数据包中处理?它们是空终止的,有一个字节长度字段,还是固定的长度? – Duck 2011-04-10 15:28:02
谢谢Peacelyk的答案! – 2011-04-10 15:32:30