Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何创建自己的数据包以通过UDP发送?_C_Sockets_Unix_Client Server - Fatal编程技术网

C 如何创建自己的数据包以通过UDP发送?

C 如何创建自己的数据包以通过UDP发送?,c,sockets,unix,client-server,C,Sockets,Unix,Client Server,我正在用C编写自己的客户机-服务器应用程序,实现TFTP协议。在阅读了TFTP的RFC并制作了一个简单的socket客户端服务器应用程序之后,现在我对如何创建必须为TFTP协议创建的特定数据包感到有点困惑 例如,WRQ数据包必须采用以下方式: 2 bytes string 1 byte string 1 byte ------------------------------------------------ | Opcod

我正在用C编写自己的客户机-服务器应用程序,实现TFTP协议。在阅读了TFTP的RFC并制作了一个简单的socket客户端服务器应用程序之后,现在我对如何创建必须为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) 如何定义字符串?因为我希望服务器接收字符串本身,并且,我认为,通过这种方式,它将在客户端机器中接收指向字符串的指针


我希望一切都很清楚,你能帮助我,因为我现在陷入困境

你不能仅仅把一个
char*
放在里面然后期望它工作,因为那是一个指针,你需要实际的字符数据出现在数据包中(在两个程序之间传递的指针几乎永远不会工作!)。由于数据包的文件名部分是可变长度的,因此不能像您尝试的那样将整个数据包表示为一个结构。相反,您可能应该通过按需连接片段来动态生成数据包,例如使用具有以下签名的函数:

vector<char> makePacket(uint16_t opcode, const char* filename, const char* mode);
vector makePacket(uint16操作码,常量字符*文件名,常量字符*模式);
以下代码(无错误检查)是建立数据包并发送数据包的一种可能方式。请注意,它假定
文件名
模式
都不为空。我不知道这是不是一个有效的假设。即使是这样,在实际代码中使用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 );

C结构不能具有可变大小。您必须将“文件名”和“模式”定义为
charfield_name[预设大小]或在运行时在内存缓冲区中手动构造结构


最后,如果您需要的是C语言中的TFTP实现,您可以打赌有人已经编写了。例如,在各种Linux发行版中都使用了BSD'ed。

在您的代码中,
char*filename是指向字符的指针。这意味着
filename
仅占用4个字节。即使字符串长度为1000字节,由于
filename
只是一个指针,它也只包含字符串第一个字符的4字节内存地址

因此有两种解决方案:使用
charfilename[MAX\u LENGTH]
声明一个大小为
MAX\u LENGTH
的字符串,并始终传递该字符串。或者,您可以包含另一个字段,例如“filename_length”,它告诉您在读取filename字段时预期的字节数

(以上事实上是错误的。
filename
的长度可能不是4字节。filename将是
sizeof(char*)
字节长。在您的计算机上可能是4字节。但指针并不总是4字节,现在人们在64位体系结构上假设4字节指针会遇到很多麻烦。所以我只是说。不要对我投反对票。)


回答第二个问题-为什么sizeof()是20字节?编译器将用额外的字节填充结构的各个部分,以便每个成员都能容纳在4字节的边界内。编译器可以有效地处理“单词”而不是大小怪异的结构。(同样,“4”取决于架构。每个架构都有自己的“字”长度。)这就是所谓的对齐。有一个非常好的SO线程提供了更多细节:

您可能会得到一个问题的答案:如何处理数据包中的字符串长度?它们是以null结尾的,有字节长度的字段,甚至是固定长度的吗?谢谢你的回答!Duck,字符串al null terminatedI认为它不能用那种方式表达,所以。。。我该怎么做?我从来没有在C中使用向量类型。。。我不知道如何使用它来确定数据包的字段。。。谢谢对不起,我说的是代码>向量< /C>但是这是C++的东西!如果您使用的是纯C,那么函数将需要返回一个C字符串(要么让它分配并返回调用方必须释放的char*,要么传入char*缓冲区和大小——我将使用后者)。我将尝试在char*buff变量中执行此操作,谢谢!