本日はじめてOKwaveを利用させていただきます、Nimameです。
以後よろしくお願いします。
本日はwinsockの送受信について質問させていただきたく、投稿しました。
現在winsockを利用したS/Cのネットワークプログラムを組んでいるのですが、
送受信の時、同PC内だとうまくいき、外部PCからだとうまくいかずに困っています。
送受信の際(recv, send)の後にSleep(10)を入れるとうまくいくことから
・パケットが最後まで送信しきれていない
・パケットが最後まで受信しきれていない
の以上が原因かと考えています。
そこでサイズ分最後まで送受信をする関数を用意したのですが、
これがどうにもうまく働いていないようでやはりうまくいきません。
--------------------------------------------------------
// 最後まで送りきる
int Send(SOCKET s, char *buf, int len)
{
int endsize;
int r;
char* sendptr = buf; // 送信する先頭アドレスを取得
// 確実に全てのパケットを送信する
while(endsize < len)
{
r = send(s, sendptr, len - endsize, 0);
// 送信結果がエラーなら終了
if( r <= 0 ) return r;
sendptr += r;
endsize+= r;
}
sendptr = NULL;
return endsize;
}
--------------------------------------------------------
// 最後まで受信する
int Recv(SOCKET s, char *buf, int len)
{
// 受信データアドレスの設定
char* recvptr = buf;
int endsize= 0;
// 受信データを1つぶん読み込むまでループする
while( endsize < len )
{
// 未受信データアドレスに実際にデータを読み込む
int r = recv(s, recvptr, len-endsize, 0);
// エラーだったら終了する
if( r <= 0 ) return r;
recvptr += r;
endsize+= r;
}
strext(buf, buf, 0, len);
recvptr = NULL;
return endsize;
}
--------------------------------------------------------
以上なのですが、おかしな点や、改善点などありましたら
お教えいただけたら幸です。
A 回答 (14件中1~10件)
- 最新から表示
- 回答順に表示
No.14
- 回答日時:
遅くなりました。
>互いにWindowsXPですが。
SPが違うとかいうレベルでしょうか。。。
いずれにしても今回とはあまり関連性が
見えてこないですね;
>まったく同じ環境、構造体です。
であれば、パディングの問題でもなさそうですが、
通信手段について、4バイトのヘッダがあると
おっしゃっていますが、下で既に出ている以外の
構造体を使用されているということでしょうか?
あとは、通信経路に少し特殊な処理系があり、
ネットワークバイトオーダの変換などをしてないとかでしょうか。。
サイズなどの数値を送る場合にバイトオーダの変換はされてますか?
# 実際に何が起こっているのかが
# 把握できていないのでこれ以上だと
# 何でも指摘してやってみないと
# どうしようも無いかもしれません。。。;
No.13
- 回答日時:
> char text[32]; です。
であれば、
>>格納されているデータはぶつ切りになる
は起こりません。構造体の中にtextの
サイズも内包されますので、
sizeof(Data)で問題ありません。
>>外部PCからだと
外部PCはサーバ側で使用してる環境と
まったく同じなのでしょうか?
念のための確認ですが、
送受信側の構造体は同じものを使っていて、
同じ環境でコンパイルされているのですよね??
この回答への補足
遅れて申し訳ありません。
>>外部PCはサーバ側で使用してる環境と
まったくおなじではありません。
互いにWindowsXPですが。
>>送受信側の構造体は同じものを使っていて、
>>同じ環境でコンパイルされているのですよね??
まったく同じ環境、構造体です。
アライメントについても同様です。
No.12
- 回答日時:
> struct Data{
> int i;
> short char text;
> }pData;
>strcpy(pData.text, "HELLO");
short char ??って型がよく分かりませんが、
上記であればそもそも、送信側のtextに領域がありません。
文字列などを格納する領域が明らかに不正でしょう。
>Send(socket, (char *)&pData, sizeof(Data));
さらに、これでは構造体分のサイズしか送られません。
最近の環境ですと、intが4byte + short であれば2byte.
charであれば1byte分のサイズのみしか送られず、
格納されているデータはぶつ切りになるでしょう。
もしも、textがポインタであるならば、
それ以前の問題ですが。。。
この回答への補足
>short char text;
誤字を指摘されつつまたも;
short char text[32]; です。
>Send(socket, (char *)&pData, sizeof(Data));
>さらに、これでは構造体分のサイズしか送られません。
そうなのですか?
以前はこの方法で無事送受信でき、
ローカル環境であれば無事に動作することから、
sizeof(Data)に特に問題がないようには思えますが・・・。
問題点と改善があればおねがいします。
No.11
- 回答日時:
> ヘッダー(4byte)は無事受信、その後のデータ受信にて
ヘッダの4byteってその後のデータのサイズということでしょうか?
> printf("%s\n", buf);
最初の投稿で載せられているコードを使っているのだと思いますが
実際にはこのbufはどのように取得された物なのでしょうか?
# 単純に文字終端入れてないだけとかじゃ。。。?
例えば、以下のようになっていませんか?
> int Send(SOCKET s, char *buf, int len)
char Hoge[] = "Hogehoge";
Send( sock, Hoge, strlen(Hoge));
~~~~~~~~~~~~
> int Recv(SOCKET s, char *buf, int len)
char buf[200];
Recv( sock, buf, sizeof(buf));
この場合受信後の格納先であるbufには'\0'終端が無いはずなので、
そのままprintfなどで表示すると、バッファーオバーランします。
この回答への補足
ヘッダー4byteはその後受信するデータタイプを格納しています。
それによって受信サイズをきめ、受信しております。
データ本体の受信には構造体を利用しています。
struct Data
{
int i;
short char text;
}pData;
strcpy(pData.text, "HELLO");
Send(socket, (char *)&pData, sizeof(Data));
-----------------------------------------------
Recv(socket, (char *)&pData, sizeof(Data));
printf("%s\n", pData->text);
No.10
- 回答日時:
映し出しミスだと思いますが、Send関数のendsize変数を初期化する際0を代入していないのは大丈夫ですか?
No.9
- 回答日時:
> WSAGetLastError()は非同期型にしているためWSAEWOULDBLOCKを返しているようです。
> 一応取得するようにはしましたが、以前変化はないようです。
WSAEWOULDBLOCK を戻しているのがわかったなら、
WSAEWOULDBLOCK に対して適切な処理を実装する必要がありますよ。
例えば、recv()可能なパケットが届くまで待ってみるとか。
例えば、timeout処理を作ってみるとか。
等です。
この回答への補足
おはようございます。今朝も寒いです。
昨日(本日)追加でかきこんだ分が反映されていなかったようで。
内部で接続ではWSAEWOULDBLOCKが発生したのですが、
外部の方に接続をしてもらったところWSAECONNRESETが発生しているようです。
始めの1度の通信(CからSへの送信)以降におきているようですが・・。
一応クライアントでは特に接続先を変えるようなアクションはしていません。
No.8
- 回答日時:
nonBloking モードで通信をしているようですが、
通信の内容が、遅れて届くのは、TCP 通信によるDELAY(遅延)
が原因だったりしませんか?
TCP通信では、転送速度を最適化するために、ネーグルアルゴリズム
と言うのを採用していますから、データ転送には、DELAYが発生したりします。
もし、転送速度よりも、応答速度を優先するのでしたら、ネーグルアルゴリズム
の無効化も試してみては如何でしょう。
他には、recv()関数が、SOCKET_ERRORを戻した場合には、
WSAGetLastError()を使って、エラー処理しましょう。
多分ですが、recv()関数が、SOCKET_ERRORを戻した場合に、
WSAGetLastError()が何を戻しているのか、デバッグ表示してみると、
解決のヒントがあるのではないかと思います。
この回答への補足
ご返答ありがとうございます。
WSAGetLastError()は非同期型にしているためWSAEWOULDBLOCKを返しているようです。
一応取得するようにはしましたが、以前変化はないようです。
ネーグルアルゴリズムの無効化ですか。
いろいろと調べてみます。
No.7
- 回答日時:
何度もすみません。
。> send関数も同様に、正常切断に対しては 0 、
> 異常切断に対しては -1 のいずれかを返却します。
と書きましたが上記は誤りです。
sendは非同期の場合0を許容しているようですね。。。
Winsock Programing QAでダウンロード可能な
リファレンス及び、MSDNに記載がありました。
# http://msdn.microsoft.com/en-us/library/ms740149 …
# http://www.sockets.com/winsock2.htm#Docs
リファレンスには、送信したバイト数、
またはSOCKET_ERRORを返すと記述されていました。
# なので 0を返す記述はありませんでしたので、
# 0 は送信したバイト数に含まれる?ものと思われます。
>No3さん
大変、失礼しました。
No.6
- 回答日時:
もうひとつ一番重要かも。
。。この通信のプロトコルは何ですか?
できれば、ソケット生成のコードなど、
もう少し全体的にコードを載せると、
早く解決できるかもしれません。
通信のプロトコルにはTCPを利用しています。
ソケット生成のコードですね。
-------------------------------------------------
// サーバー(自身)
int Init()
{
// Winsockの設定
WSADATA data;
WSAStartup(MAKEWORD(2,0), &data);
// ソケットの生成
srvSocket = socket(AF_INET, SOCK_STREAM, 0);
if (srvSocket == INVALID_SOCKET)
{
printf("socket failed\n");
return 1;
}
// Addr構造体のセット
srvAddr.sin_family = AF_INET;
srvAddr.sin_port = htons(PORT);
srvAddr.sin_addr.S_un.S_addr = INADDR_ANY;
dstAddrSize = sizeof(dstAddr);
// ソケットのバインド
bind(srvSocket, (struct sockaddr *) &srvAddr, sizeof(srvAddr));
// 接続の許可
listen(srvSocket, 1);
// 正常終了
return 0;
}
接続してきたクライアントに対してはacceptした後、そのsocketに対し、
u_long val=1;
ioctlsocket(socket, FIONBIO, &val);
//------------------------------------------------------
// クライアント
if(connect(dstSocket, (struct sockaddr *) &dstAddr, sizeof(dstAddr))) return -1;
No.5
- 回答日時:
> sendは送信時に「ネットが詰まってて送れない時」には
> 「0バイト送信した」で0で返って来る。
> recvも受信時に「ネットが詰まっててまだデータが来ない時」
> には「0バイト受信した」で0で返って来る。
そんな事は無いと思いますが。。。
recv関数は、接続が正しくシャットダウンを
実行した場合に 0 となります。それ以外のエラーは
(タイムアウトも含めて)-1となるはずです。
send関数も同様に、正常切断に対しては 0 、異常切断に対しては -1 のいずれかを返却します。このとき WSAGetLastError() の返却値は、上記の recv() のときと同様のエラーが返されます。
# これはPOSIXでもWINSOCKでも広域エラー領域に対する設定値が
# 異なるだけで動作的には同じはずですが。。。
> これがどうにもうまく働いていないようで
どううまく動かないのでしょう?
送っているデータは文字列ですが?
数値などを含むバイナリですか?
参考URL:http://www.kt.rim.or.jp/~ksk/wskfaq-ja/articles/ …
この回答への補足
>>どううまく動かないのでしょう?
ヘッダーとデータを分けて受信しているのですが
ヘッダー(4byte)は無事受信、その後のデータ受信にて
大量の記号?ですか?文字化けのようなものが受信されてしまいます。
*printf("%s\n", buf);
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
誕生日にもらった意外なもの
みなさんがもらった誕生日プレゼントで面白いものがあったらぜひ教えてください!
-
フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
あなたが普段思っている「これまだ誰も言ってなかったけど共感されるだろうな」というあるあるを教えてください
-
映画のエンドロール観る派?観ない派?
映画が終わった後、すぐに席を立って帰る方もちらほら見かけます。皆さんはエンドロールの最後まで観ていきますか?
-
海外旅行から帰ってきたら、まず何を食べる?
帰国して1番食べたくなるもの、食べたくなるだろうなと思うもの、皆さんはありますか?
-
天使と悪魔選手権
悪魔がこんなささやきをしていたら、天使のあなたはなんと言って止めますか?
-
Winsockで接続待ちタイムアウトを設定する方法
C言語・C++・C#
-
Connectエラーが出てしまう・・・。
C言語・C++・C#
-
recv関数の戻り値について
C言語・C++・C#
-
-
4
非ブロッキングソケットのrecvについて
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・漫画をレンタルでお得に読める!
- ・街中で見かけて「グッときた人」の思い出
- ・「一気に最後まで読んだ」本、教えて下さい!
- ・幼稚園時代「何組」でしたか?
- ・激凹みから立ち直る方法
- ・1つだけ過去を変えられるとしたら?
- ・【あるあるbot連動企画】あるあるbotに投稿したけど採用されなかったあるある募集
- ・【あるあるbot連動企画】フォロワー20万人のアカウントであなたのあるあるを披露してみませんか?
- ・映画のエンドロール観る派?観ない派?
- ・海外旅行から帰ってきたら、まず何を食べる?
- ・誕生日にもらった意外なもの
- ・天使と悪魔選手権
- ・ちょっと先の未来クイズ第2問
- ・【大喜利】【投稿~9/7】 ロボットの住む世界で流行ってる罰ゲームとは?
- ・推しミネラルウォーターはありますか?
- ・都道府県穴埋めゲーム
- ・この人頭いいなと思ったエピソード
- ・準・究極の選択
- ・ゆるやかでぃべーと タイムマシンを破壊すべきか。
- ・歩いた自慢大会
- ・許せない心理テスト
- ・字面がカッコいい英単語
- ・これ何て呼びますか Part2
- ・人生で一番思い出に残ってる靴
- ・ゆるやかでぃべーと すべての高校生はアルバイトをするべきだ。
- ・初めて自分の家と他人の家が違う、と意識した時
- ・単二電池
- ・チョコミントアイス
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
CStringをwchar_tに変換したい
-
main の引数には const 付けた方が
-
AnsiPos相当の関数はありません...
-
fgetsなどのときのstdinのバッ...
-
文字列から空白を取り除きたい...
-
ネットワークにつながっている...
-
テキストデータをそのままバイ...
-
charからLPTSTRへの変換方法
-
型変換
-
間接操作のレベルとは
-
int main()の・・・
-
phpMyAdminからストアドプロシ...
-
英単語をアルファベット順に
-
sprintfに同じ変数は使えるか
-
日付表示の方法
-
ソースコードエラー
-
C言語 バイナリファイルをfloa...
-
文字列ポインタを結合
-
16進数から10進数に変換
-
char型からのバイト数取得
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
fgetsなどのときのstdinのバッ...
-
CStringをwchar_tに変換したい
-
charでの計算?
-
文字列から空白を取り除きたい...
-
charからLPTSTRへの変換方法
-
'const char *' 型は 'char *' ...
-
テキストデータをそのままバイ...
-
配列をnビットシフトする
-
半角カナ→16進
-
double型の値をchar配列に変換...
-
sprintfに同じ変数は使えるか
-
ファイル名である文字列からbas...
-
ネットワークにつながっている...
-
ftoa の作り方
-
間接操作のレベルとは
-
型変換
-
C言語です
-
C言語のfor文です。 繰り返しの...
-
Win32APIでのエディットボック...
-
【C言語】文字型と整数型の違い
おすすめ情報