我在C中创建自己的客户端 - 服务器应用程序,实现TFTP协议。在阅读TFTP的RFC并使用简单的套接字客户端 - 服务器应用程序之后,现在我对如何创建必须为TFTP协议创建的特定数据包感到困惑。
例如,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
};
我有两个疑问:
a)当我创建sizeof(struct WRQ)时,它返回20个字节。这不是我想要的尺寸。为什么会这样?
b)我如何定义字符串?因为我希望服务器接收字符串本身,而且,我认为,这样,它将收到客户端计算机中字符串的指针。
我希望一切都清楚,你可以帮助我,因为我现在卡住了!
答案 0 :(得分:2)
以下代码(没有错误检查)是构建数据包并发送数据包的一种可能方法。请注意,它假定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 );
答案 1 :(得分:1)
你不能只在那里放一个char*
并希望它能够工作,因为那是一个指针,你需要在数据包中显示实际的字符数据(在两个程序之间传递的指针几乎不会工作!)。由于数据包的文件名部分是可变长度的,因此您无法将整个数据包表示为您尝试执行的结构。相反,您可能应该通过按需连接各个部分来动态生成数据包,例如使用具有此签名的函数:
vector<char> makePacket(uint16_t opcode, const char* filename, const char* mode);
答案 2 :(得分:1)
在您的代码中,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?
答案 3 :(得分:0)
C结构不能具有可变大小。您必须将“filename”和“mode”定义为char field_name [preset size];
,或者在运行时手动在内存缓冲区中构造结构。
最后,如果您需要的是C中的TFTP实现,您可以打赌有人已经写过了。例如。在各种Linux发行版中都使用了BSD'ed tftp-hpa。