- ベストアンサー
winsockで送受信されるデータの効率的な扱い方について
Winsock2.hを使って通信プログラムを作っています。 座標などのパラメータを短いスパンで送受信して処理をするものなのですが、 send()で送れるデータ型がchar*型ということなのでパラメータをwsprintf()を使って SOCKET s; int x=100; int y=100; int z=100; char buf[16]; wsprintf(buf,"#%04d#%04d#%04d",x,y,z); send(s,buf,strlen(buf),0); のようにして送信して、受信されたデータはstrtok()で区切りながらそれぞれ格納しています。 SOCKAT s; int x,y,z; int nResult; char buf[16]; char *tp; nResult = recv(s,buf,sizeof(buf),0); tp = strtok(buf,"#"); x=atoi(tp); tp = strtok(buf,"#"); y=atoi(tp); tp = strtok(buf,"#"); z=atoi(tp); という感じなのですが、パラメータが増えていくにつれなんというか冗長というか、 もうちょっと賢いやり方があるような気がしていろいろ調べてはみたものの… あまりデータの扱い方に関しての解説が見つからなかったので質問させていただきました。 ということで、他に複数の変数を纏めて送受信して処理する手法(できれば高速に)をご存知でしたらご教授お願いします。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
#1です。 すいません。なんか誤ってプログラム部分だけ送信してしまいました。 sendの引数はchar*ですが、別にバイナリーデータを送信しても問題ありません。 同じi386CPUのWindowsマシン間で通信する、という条件があるのでしたら、送信データを構造体にして、構造体のデータを送信するのが一番てっとりばやいと思います。 その具体例が#1のソースになります。 なお、ソースは動作は確認しておりません。 あしからずご了承ください。
その他の回答 (2)
- chie65536(@chie65535)
- ベストアンサー率44% (8740/19838)
#1の回答にあるように「バイナリデータのまま送受信」が効率的ですが、その場合は、longやintやshortの扱いに注意しましょう。 送信側と受信側で、intやshortのデータの「バイト並び順」が一致している保証は無いので「バイトの並び順を統一する」必要があります。 以下のページを参考に http://msdn.microsoft.com/ja-jp/library/3thek09d(VS.71).aspx 送信側では「ホストのバイト順からネットワークのバイト順に変換」を、受信側では「ネットワークのバイト順からホストのバイト順に変換」を行う必要があります。 送信側の例(x,y,zは32ビットと想定) senddata.x = htonl(x); senddata.y = htonl(y); senddata.z = htonl(z); 受信側の例(x,y,zは32ビットと想定) x = ntohl(senddata.x); y = ntohl(senddata.y); z = ntohl(senddata.z);
お礼
回答ありがとうございます。 他の方法を調べていたとき、構造体を送る方法も見つけたのですがエンディアンの都合であまりお勧めできないというようなことが書いてあって見送っていたのですが、 ネットワークバイトオーダーの変換を利用すればよかったんですね。
- i-kujou
- ベストアンサー率50% (13/26)
typedef struct _TSendData { int x; int y; int z; } TSendData; // 送信側 int SendData(SOCKET s, int x, int y, int z) { // 送信データの作成 TSendData senddata = {0}; senddata.x = x; senddata.y = y; senddata.z = z; int done = 0; int r; char* sendptr = (char*)&senddata; // 送信する先頭アドレスを取得 // 送信データを全て送り終わるまでループする while( done < sizeof(TSendData) ) { // 未送信の部分を送信してみる r = send(s, sendptr, sizeof(TSendData) - done, 0); // 送信結果がエラーなら終了 if( r <= 0 ) return r; // 未送信データアドレスと送信完了バイト数を更新 sendptr += r; done += r; } return done; } // 受信側 // 返り値は読み込んだバイト数orエラーコード // data に受信結果が挿入される int RecvData(SOCKET s, TSendData* data) { // 受信データアドレスの設定 char* recvptr = (char*)data; int done = 0; // 受信データを1つぶん読み込むまでループする while( done < sizeof(TSendData) ) { // 未受信データアドレスに実際にデータを読み込む int r = recv(s, recvptr, sizeof(TSendData)-done, 0); // エラーだったら終了する if( r <= 0 ) return r; // 未受信データアドレスと受信完了バイト数を更新 recvptr += r; done += r; } return done; }
お礼
回答ありがとうございます。 バイナリで送れたんですね。 パラメータが増えてきて複雑なトークン分けを行っていたのでおかげでかなり楽になりました。