自前の通信プロトコルの実装

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
shiro4ao

自前の通信プロトコルの実装

#1

投稿記事 by shiro4ao » 15年前

バイト数,データ
となっている、データがTCPソケットでsend()されます。
例)10,1234567890
7,abcdefg

このデータの部分を途中で切れることなく送った通りに受け取りたいのです。
例)
10,1234567890
が送られてきたら
1234567890
とバッファに入って欲しい
123
で一旦途切れて、
4567890
と来てほしくない

以下のように書いたのですが、実行すると10バイト送った場合、
後ろにゴミと思われるデータがくっついてバッファに書き込まれました。
何か解決方法はありますか?
それとも根本的におかしいのでしょうか?


====================ここから=============================================
int recvex (SOCKET sock, char * buf, int len,int flags )
{
int ret,ret2=0,i;
BOOL Flag=TRUE; // データ長を示す部分が有るか無いか
char *size,tmp1[1024],*tmp2;
size = (char *)malloc(sizeof(char));
tmp2 = (char *)malloc(sizeof(char));
memset(buf,'\0',sizeof(buf));
memset(tmp2,'\0',sizeof(tmp2));
memset(tmp1,'\0',sizeof(tmp1));


//データ長と同じサイズになるまでrecvする
while(ret2==atoi(size)){
if(Flag){
//ここはデータ長の部分が含まれている時の処理
ret= recv(s,tmp1,100, flags);
CmdTok(tmp1,",",2,&tmp2);
strcat(buf,tmp2);
ret2=strlen(tmp1)+ret2;

//データ長の取得
DataTok(tmp1,",",1,&size);
Flag=FALSE;
}else{
//ここはデータ長移行の部分の処理
memset(tmp2,'\0',sizeof(tmp2));
ret= recv(s,tmp2,100, flags);
strcat(buf,tmp2);
ret2=ret+ret2;
}


}

return ret2;
}

//bufから、第三引数が1なら","以前の部分を、2なら","移行の部分を取り出す
int DataTok(char *buf ,char *div,int n ,char **ret){
int i;
*ret = strtok(buf,div);
for(i=0;i<n-1;i++) *ret = strtok(NULL,div);
return 0;
}
====================ここまで=================================================

toyo

Re:自前の通信プロトコルの実装

#2

投稿記事 by toyo » 15年前

mallocとstrtokの使い方が良くわかっていないように思います
tmp2 = (char *)malloc(sizeof(char));
ですが
sizeof(char)は1ですので
tmp2 = (char *)malloc(1);
となりtmp2には1バイトの領域しか確保されません
char tmp2[1];
と同じ意味になります
strtokの返り値を受けるもののようなのでその場合mallocする必要はないです
freeするのも忘れています
もちろんこのままfreeしてもポインタの値が変わっているのでエラーになってしまいますが
memset(tmp2,'\0',sizeof(tmp2));
もいらないというか問題を悪化させています
sizeof(tmp2)はポインタのサイズなのでおそらく4になります(64ビット用にコンパイルする場合は8)
1バイトの領域しかないのに4バイト0にするので問題です
結論として
size = (char *)malloc(sizeof(char));
tmp2 = (char *)malloc(sizeof(char));
memset(tmp2,'\0',sizeof(tmp2));
は必要ないです
memset(buf,'\0',sizeof(buf));
も考えた方がいいでしょう

toyo

Re:自前の通信プロトコルの実装

#3

投稿記事 by toyo » 15年前

次にstrtokですがこれは引数に渡した文字列を破壊していきます
文字列を後でまた使いたいときには別にコピーを保存しておかないといけません
CmdTok(tmp1,",",2,&tmp2);
の時点でtmp1は破壊されているのでこの後
strlen(tmp1)
しても期待した値は得られません
ret2==atoi(size)
の部分もsizeを初期化してないのでよくないです

質問のゴミがつく問題ですがこれは
memset(tmp2,'\0',sizeof(tmp2));
で最初の4バイトしか0にしてないのが原因でしょう
memset(tmp2,'\0',100);
にすればとりあえずゴミはなくせると思います

YuO

Re:自前の通信プロトコルの実装

#4

投稿記事 by YuO » 15年前

> データがTCPソケットでsend()されます。
> このデータの部分を途中で切れることなく送った通りに受け取りたいのです。

前提条件がおかしいです。
TCPは「データ送信境界が保持されない」ものなので,
「途中で切れることなく送った通りに受け取りたい」を満たすプロトコルではありません。
「途中で切れることなく送った通りに受け取りたい」が重要であればUDPなどのプロトコルを使うべきですし,
TCPの各機能 (再送とか欠損のチェックなど) が重要であれば,送信と受信が一対一でないことを前提としてプログラムを組むべきです。

今回の場合,先頭にサイズが含まれるのですから,それを使ってサイズを決定するべきでしょう。

SITE: Winsock Programmer's FAQ: Articles: The Lame List
http://www.kt.rim.or.jp/~ksk/wskfaq-ja/ ... tml#item20

shiro4ao

Re:自前の通信プロトコルの実装

#5

投稿記事 by shiro4ao » 15年前

>toyoさん
1バイトしか割り当てられていなかったのですね。
仕組みがよくわかりました。

>YuOさん
ご紹介のサイトで、自分がいろいろ誤解をしていたことがわかりました。


どうしても上手くいかなかったのでプロトコルを変更して
実装したら、希望どおりの動作になりました。
ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る