2011-04-10 16 views
3

TFTPプロトコルを実装しているCで私自身のクライアントサーバーアプリケーションを作っています。 TFTPのRFCを読んでシンプルなソケットクライアント/サーバーアプリケーションを作った後は、TFTPプロトコル用に作成しなければならない特定のパケットを作成する方法について少し混乱します。自分のパケットをUDP経由で送信するにはどうしたらいいですか?

 2 bytes  string 1 byte  string 1 byte 
     ------------------------------------------------ 
     | Opcode | Filename | 0 | Mode | 0 | 
     ------------------------------------------------ 

公式RFCから抽出される:

たとえば、WRQパケットは、この方法でなければなりません。

私はパケットのすべての構造を定義する.hを持っていますが、私が正しくやっているかどうかわかりませんし、ウェブ上で情報を見つけるのは幸運でもありません。

私はこのパケットのために作成された構造体は次のとおりです。私ははsizeofを作るとき

a)は(構造体は、WRQ)が20のバイトを返します。私は2つの疑問を持って

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

。これは私が手に入れたいサイズではありません。なぜこれが起こるのですか?

b)文字列をどのように定義する必要がありますか?サーバーが文字列自体を受け取るようにしたいと思うので、この方法では、クライアントマシンの文字列へのポインタを受け取ることになります。

私はすべてがはっきりしていると私は瞬間に立ち往生しているので、私を助けることができることを願っています!

+0

をあなたは、あなたの質問http://stackoverflow.com/questions/5596428/sizeofstruct-returns-unexpected-value – Peacelyk

+0

質問に対する答えを得る可能性があります扱われるパケットで?それらはヌルで終端されているか、バイト長のフィールドを持っていますか? – Duck

+0

Peacelykさん、ありがとうございました! –

答えて

1

コードでは、char * filename;はcharへのポインタです。つまり、filenameは4バイトしか占有しません。たとえ文字列が1000バイトであっても、filenameは単にポインタにすぎないので、文字列の最初の文字の4バイトのメモリアドレスを含んでいます。

したがって、char filename[MAX_LENGTH]を使用して、サイズMAX_LENGTHの文字列を宣言し、常にそれを渡します。または、別のフィールド、たとえば "filename_length"を含めることができます。これは、ファイル名フィールドの読み込み時に予想されるバイト数を示します。

(上記は実際には偽です。ファイル名はsizeof(char*)バイトですが、これはおそらく4バイトですが、ポインタは必ず4バイトではなく、現在では64ビットアーキテクチャ上で4バイトのポインタを仮定するために多くのトラブルが発生するので、私はちょうどsayin 'です。私をdownvoteしないでください)

あなたの2番目の質問に答えるには - sizeof()は20バイトですか?コンパイラは、各要素が4バイトの境界内に収まるように、構造体の断片に余分なバイトを埋め込みます。コンパイラは、奇妙なサイズの構造ではなく、単語で効率的に動作することができます。 ( "4"はアーキテクチャにもよりますが、各アーキテクチャには独自の "word"長さがあります)。優れたが、SO詳細与えるスレッドがあります:文字列の長さはどのように:Why isn't sizeof for a struct equal to the sum of sizeof of each member?

1

char*をそこに置くことはできません。これはポインタなので、実際の文字データをパケットに表示する必要があります(2つのプログラム間で渡されるポインタはほとんど動作しません)。パケットのファイル名部分は可変長なので、しようとしているように構造体としてパケット全体を表現することはできません。代わりに、あなたはおそらく、動的なこのシグネチャを持つ関数と同様に、オンデマンドで駒を連結してパケットを生成する必要があります:

vector<char> makePacket(uint16_t opcode, const char* filename, const char* mode); 
+0

私はそれがそのように表現することはできないと思ったので...どうすればいいですか?私はベクトルでタイプを使用したことがない...私はパケットのフィールドを決定するためにそれを使用する方法を知らない...ありがとう! –

+0

申し訳ありません、私は 'ベクトル'と言いましたが、これはC++のものです!ストレートCを使用している場合、関数はCの文字列を返す必要があります(呼び出し側が解放しなければならないchar *を割り当てて返すか、char *バッファとサイズを渡します)。後者)。 –

2

を(なしエラーチェックと)次のコードのパケットを構築する1つの可能な方法でありますそれを送信します。 filenamemodeの両方が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); 
+0

私はこれを試してみましょう!ありがとう! –

0

C構造体は、可変サイズを持つことができません。 "filename"と "mode"をchar field_name [preset size];と定義するか、実行時にメモリバッファに手動で構造体を構築する必要があります。

最後に、必要なものがCのTFTP実装であれば、誰かが既に書いていると賭けることができます。例えば。さまざまなLinuxディストリビューションにBSDのtftp-hpaが使われています。

+0

私はそれをchar * buff変数でやってみましょう、ありがとう! –

関連する問題