• ベストアンサー

recv関数の受信結果について

send関数で送信、recv関数で受信をPG内で繰り返してます。 (MAIL、RCPT等) この時、recv関た数が受け取るメッセージは内部ではどうなって いるのでしょうか? 1.実行分だけたまる 2.最後の実行が上書きされる。 1の場合、どこかでそのエリアをクリアしないとメモリリークが 起きるのかな?と心配があります。 もし、1であればエリアをクリアする方法をご教授頂ければ と思います。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
  • lv4u
  • ベストアンサー率27% (1862/6715)
回答No.4

>>内部の領域は"250 OK220 OK\0"となるのでしょうか? 通常、socket通信は、送信するバイト列をバイナリとしてそのまま送信するので、'\0'を最後に送信していれば、上記のようになるでしょうし、送ってなければ、'\0'は届かないですね。Cの文字列のような'\0'が文字列の終わりのような役割は無いです。もしそうであれば、intやlongのデータをそのままでは送れないことになってしまいます。 そして通常は構造体を丸ごと送信するケースが多いようです。 ただ、「そのまま送る」といっても、例えば100bytesを1回でsendしたとき、「100bytesのパケットが飛ぶ」とは限りません。100bytesを1回でrecvしたり、50bytesが2回、またちょっと考えにくいのですが、1byteを100回recvするということになるかもしれません。 socketはパケットというよりも、「ダラダラと続くバイト列が適当に切られてrecvされる」と考えたほうがいいと思います。 >>ここで220から読むには読み捨てが必要になるのでしょうか? ネットワークのエラー等で再送されたデータなど、ほんとにいらないデータなら読み捨てですが、処理に必要なデータなら処理します。通常は、先頭に長さデータの情報を付加したり、データ内に出現しないコードを区切り文字として、受信したバイト列を、送信時のパケットあるいは1レコードとして復元させます。たとえば、"250 OK220 OK"のデータなら、基本的に6バイト読んで1レコードという処理を2回することになります。 実際の処理では、通信経路上のノイズや処理遅延などでデータ欠落が発生したりするため、シーケンスNoなどで、受信したレコードが正しいか確認する処理を行います。 注:実際には、ネットに流すデータはバイトオーダも考慮してください。

derby
質問者

お礼

ありがとうございます。 もうすぐ単体試験が始まるので、不具合が出た際は 参考にしたいと思います。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (3)

  • a-saitoh
  • ベストアンサー率30% (524/1722)
回答No.3

OS側でrecv()でメモリリークが起きるかどうかはOSの問題です。 いづれにせよ、このような単純なメモリ管理方式はとっていません。 >1.実行分だけたまる >2.最後の実行が上書きされる。 少なくとも、UNIX系OSに関しては、recv/sendなどソケット系システムコールでメモリリークは起こりません。 というか、「OS内部でどうメモリを使っているかアプリケーションプログラマが考えて、メモリリークを起こさないように気をつけてプログラミングする」というのはWindowsなど腐れたOSの話です。ソケットAPIではそのような制約はありません。受け取ったパケットをrecvで取り出さなければある程度までメモリ消費量が膨らみますが、いずれにせよcloseした時点ですべて元に戻ります。

derby
質問者

お礼

ありがとうございます。 メモリに関して心配なさそうですね。

全文を見る
すると、全ての回答が全文表示されます。
  • lv4u
  • ベストアンサー率27% (1862/6715)
回答No.2

send,recv関数で行うソケット通信は、OSで送受信用バッファが用意されます。これに余裕がある間は、送信受信が行われますが、一杯になれば、バッファに空きができるまで停止します。また、ネットワークにデータを流す送受信の単位は、TCPパケットの送受信の最適化をするため、1バイトずつ送ったとしても、受信側に1バイト単位で届くということはないようです。 それから、受信分が貯まった場合の問題は、空きが無くなるメモリーパンク状態で、メモリーリークではないですね。 もし、ゴミデータだと判別できるなら、読み捨てをやればいいと思いますし、この処理が必要なケースはよくあると思います。

derby
質問者

補足

やはり読み捨てでしょうか? 例えば、 1回目が「250 OK」で2回目が「220 OK」だとして、 内部の領域は"250 OK220 OK\0"となるのでしょうか? recvで最初に3バイト取得すると、次は250のスペースからに なりますか? ここで220から読むには読み捨てが必要になるのでしょうか? よろしくお願いします。

全文を見る
すると、全ての回答が全文表示されます。
  • a-saitoh
  • ベストアンサー率30% (524/1722)
回答No.1

言語は何でしょうか? Cだったら、recvがつかうデータエリアは呼び出し側が用意して渡すので、メモリリークが起きるかおきないかはrecvをつかうプログラムしだいです。

derby
質問者

補足

ありがとうございます。 言語はCです。 recvでの応答メッセージの先頭3バイトだけでいいので、 3バイト分用意して、取得しています。 読み捨てる分は影響なしと考えていいでしょうか?

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • recv 受信

    送信データが 1500BYTE以上の場合、recvで完全な受信ができない場合、どんな対策が御座いますか?教えて下さい. 因みに、recvは以下のように実行しています. recv(sock, bBuf, size, 0);

  • recv関数の戻り値について

    おせわになります。 socket関数(WinSock2)のrecv関数のことで質問なのですが、 第4引数にMSG_PEEKを指定したときと、指定しない時(=0) の戻り値が、明らかに違うのです。 実際は、20000バイトを送信し、受信側でrecvすると、 MSG_PEEKを指定すると、8760が返り、 MSG_PEEKを指定しない(=0)と、20000が返ります。 (もっと試して、200000と10倍にしても一回で受信しました。) recvが一度に受信できる容量のテストをしていたときに発見したのですが、こういうものなのでしょうか? 以上、よろしくおねがいします。

  • socket: recvはいつ,どれだけ受け取るのか?

     現在,参考書にしたがってC++でソケットプログラミングを書いています.  sendとrecvを非同期にするために,本では select関数やWSAAsyncSelect関数などを利用していて,実際,本のとおりに書いて上手く動いています.  ここで伺いたいのですが,recvは,どうやって「データが届いたか」を知るのでしょうか.  同期ならば,トランシーバでの会話のように送信側が「どうぞ」といって送受信を交代させることができますが,非同期ならばそれができません.  NICとかが,プログラムに「届いたぞ!( or これから届くぞ!)」と教えてくれるのでしょうか.あるいは逆に,プログラムがNICに「届いてる?」と聞いているのでしょうか.仮に,ここに書いたような方法で届いたことが分かったとしても,どれくらい受け取ればいいかは分かりません(それも併せて教えてもらっているのでしょうか.データを送るときには,どれだけ送ればいいか分かりますよね.受信するときはどうしてるのかを知りたいと思っています).

  • ファイルの受信

    c言語で、クライアント側のファイルを開き、内容をそのまま送信しているはずなのですが上手くいきません。 テキストファイルは正しく送れるようですが、他の実行ファイルなどはダメみたいです。 送信側は、"rb"でオープンし,whileで fread(send_buf,1024,1,fp); send(soc,send_buf,strlen(send_buf),0); を繰り返しています。send_buf[1025]です。 送信側は Recv_buf[1025];で size = recv(soc,Recv_buf,1024,0); fwrite(Recv_buf,size,1,fp); whileで繰り返し受信がなくなったらselectでタイムアウトしています。 いろいろ調べたのですがSleepが必要らしいそうですが・・・どうなんでしょう?

  • 延々と受信し続けるwinsockのrecv

    以下のサーバープログラムを用いて、 (acceptしたらスレッド作成し、作成が終ったということをクライアントに知らせるために文字列送信後受信待機している) #include <winsock2.h> #include <vector> #include <process.h> #include <algorithm> char *Ver = "0.00"; using namespace std; unsigned __stdcall Patch( void *Sock ); int main() { ----WSADATA wsaData; --------WSAStartup( MAKEWORD(2,0), &wsaData ); ----SOCKET RecvSock = socket( AF_INET, SOCK_STREAM, 0 ); ----SOCKET SendSockBuf; ----vector<SOCKET> SendSock; ----fd_set ConnectFds, SubConnectFds; ----struct sockaddr_in Recv, Send; ----int len = sizeof(Send); ----Recv.sin_family = AF_INET; ----Recv.sin_port = htons(55555); ----Recv.sin_addr.S_un.S_addr = INADDR_ANY; --------bind(RecvSock, (struct sockaddr *)&Recv, sizeof(Recv) ); ----FD_ZERO( &SubConnectFds ); --------FD_SET( RecvSock, &SubConnectFds ); ----listen( RecvSock, 5 ); ----vector<unsigned int> thID; ----vector<HANDLE> hTh; ----struct timeval tv; --------tv.tv_sec = 0; --------tv.tv_usec = 0; ----while(1) ----{ --------memcpy( &ConnectFds, &SubConnectFds, sizeof(fd_set) ); --------select( 0, &ConnectFds, NULL, NULL, &tv ); --------if ( FD_ISSET(RecvSock, &ConnectFds) ) --------{ ------------SendSockBuf = accept(RecvSock, (struct sockaddr *)&Send, &len); ------------if( SendSockBuf != INVALID_SOCKET) ------------{ ----------------SendSock.push_back( SendSockBuf ); ----------------thID.push_back( hTh.size() ); ----------------hTh.push_back( (HANDLE)_beginthreadex(NULL, 0, Patch, &SendSock[hTh.size()], 0, &thID[hTh.size()]) ); ------------} --------} ----} ----closesocket(RecvSock); ----WSACleanup(); ----return 0; } unsigned __stdcall Patch( void *Sock ) { ----SOCKET *SendSock = (SOCKET *)Sock; ----send( *SendSock, Ver, 5, 0 ); ----char Str[5]; ----while( Flag == 0 ) ----{ --------recv( *SendSock, Str, 5, 0 ); ----} ----closesocket( *SendSock ); ----return 0; } 以下のようなクライアントプログラムで文字を送信すると、 #include <WinSock2.h> using namespace std; void main() { ----WSADATA wsaData; --------WSAStartup( MAKEWORD(2,0), &wsaData ); ----SOCKET Sock = socket( AF_INET, SOCK_STREAM, 0 ); ----struct sockaddr_in Addr; --------Addr.sin_family = AF_INET; --------Addr.sin_port = htons(55555); --------Addr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); ----connect( Sock, (struct sockaddr *)&Addr, sizeof(Addr) ); ----char str[5]; ----recv( Sock, str, 5, 0 ); ----send( Sock, "0.00", 5, 0); ----shutdown( Sock, 2 ); ----closesocket( Sock ); } クライアントプログラムは終了しているのにサーバープログラムは"0.00"を受信し続けます。 どこがおかしいのか分からないので教えてください

  • SocketのSend関数でのCLOSEの検知 [Linux]

    Linux環境でSocket(dm:PF_INET,type:SOCK_STREAM)を使用しての、 Client&ServerプログラムをCで作成しているのですが、 そこでのSend関数の使い方についてご助力ください。 Client&Serverプログラムは下記のような動きをします。 [Client] ServerへConnectした後、複数のDataを数秒間隔でServerへ 送信(send関数使用)します。受信(recvやread関数等)は、 一切行いません。 [Server] ClientからのConnectを受け付けた後、Clientから受信(recv関数 使用)したDataを標準出力へ表示する。送信(sendやwrite関数 等)は、一切行いません。 さて、ここでもしClientプログラムがCloseを発行したり、マシン DOWN等の理由でConnectionが切断され、Server側のSocketが CLOSE_WAIT状態になった場合、Bufferに溜まっていたDataを すべて受けきった後、recv関数が0を返してくれるので 相手が終了したことがわかります。 ここからが質問のMainです。 では、もしServerプログラムがCloseを発行したり、マシン DOWN等の理由でConnectionが切断され、Client側のSocketが CLOSE_WAIT状態になっても、CLOSE_WAIT直後のsend関数が なぜか正常に処理されてしまいます。無論このDataは、 Server側は受け取りません。この次のsend関数実行時に EPIPEが返ってくるので、ここでようやくSocketが切断された ことが判ります。 これを何とかCLOSE_WAIT状態になった直後から、send関数で 切断を検知できるようにできないでしょうか。 よろしくお願いします。 以上

  • 配列とポインタについて

    こんばんわ。 WinSockを利用してネットワークプログラミングを行っています。 以下のようなプログラムを作成したのですが、実行できません。 以下のプログラムは質問箇所を抜き出したものです。 [プログラム] int Receive(u_short portNo) { char recv_Buf[1025],recv_Buff[1025]; size = recvfrom(s2, recv_Buf, (int)sizeof(recv_Buf) - 1, 0, (SOCKADDR *)&from, &fromlen); recv_Buff = recv_Buf; Sender(portNo,szServer,recv_Buff); } int Send(unsigned short portNo,char *szServer,char *recv_Buff) { sendto(s1, recv_Buff, (int)strlen(recv_Buff), 0, (LPSOCKADDR)&addrin1, sizeof(addrin1)); } このプログラムは、Receive関数内のrecvfrom関数で1024Byte(recv_Buf[1025])受信したデータをSend関数内のsendto関数で送信するというプログラムです。 recv_Buf = recv_Buffにてエラーが発生します。なにか解決策はりますでしょうか? また、Receive関数およびSend関数は何回も呼ばれるのですが、配列は初期化する必要があるのでしょうか? よろしくお願いします。

  • 0byteデータの送信と受信

    現在unixでsocketプログラムを書いています。 FTPライクなプログラムを書いているのですが、ファイルを送受信する場合、ファイルの終端をどうするかを考えています。 ファイルサイズを送るのはなしです。 sendで0byteのデータを送り、recvで0byteのデータを受信した場合にファイルの終端に達したとして処理を終らせたいと考えています。 実際、sendでは0byteのデータを送信してもエラーにはなりませんが、recvでは受信できません。 そのような処理はできるのでしょうか? よろしくおねがいします。

  • winsock recvでデータの取得方法

    sendで送られてきたデータをrecvで取得しています。 recvで取得したあと'\0'を入れないと文字化けを起こしてしまうので'\0'を入れているのですが、そうすると送信したバイト数と違ってきます。 同じバイト数にしたいのですが、いろいろ試しましたが、うまくいきません。  ご存知の方いらっしゃいましたら、教えてください。 また、recvで受けるときは、バイト数が多くなるのは、仕方がないのでしょうか? // ------------------ ソース -------------------- DWORD byteResult; ofstream fileWrite; byteResult = 0; while(byteResult < 最大バイト数){ nResult = recv(client_s, (CHAR *)pbuff, 7000, 0); <-- 一括で最大バイト数で受信をしたいのだが、途中で文字化けを起こすので、7000バイトに区切って受信。 pbuff[nResult + 1] = '\0'; try{ fileWrite.open("D:\\suzuki\\LogOutTest\\outdir.txt", ios::app); fileWrite << pbuff; fileWrite.close(); }catch(CException e){ fileWrite.close(); return -1; } byteResult += nResult; } delete[] pbuff; よろしくお願いします。

  • TCPのプログラミングで質問…というか確認しておきたいことが…

    このたびC言語でネットワークプログラミング(TCP)をしているのですが、気になったことがあったので、2点ほど質問させていただきます。 (1)WSock32のsendで一度に送信できる量は65535バイトと以前学んだのですが、受信側がrecvする前にどんどん65535バイト送信していったら受信側のソケットはどんどんいっぱいになってしまいますよね?その場合、限界はあるのでしょうか?また、一度にrecvできる量も65535バイトが限界なのでしょうか?もしそうだとしたら65535バイト以上データがあると取得しても残ってしまうんですか? (2)sendで大きなデータなどを送信した場合、受信側でrecvしたときに途中までのデータを受信してしまったりすることってありますか?たとえば、「"abcde"と送信したのに対し、受信側でrecvしたらとりあえず"abc"まで受信し、次のrecvで残りのデータを受信する」様なことってあるんでしょうか? すべてのデータがちゃんと送信されてからじゃないとrecvで取得することはできなくなっているんでしょうか… とてもとても分かりにくい文章で本当にすみません。 すべてとはいいません、少しでも情報があれば教えていただけませんでしょうか・・・ どうぞよろしくお願いいたしますm(_ _)m

このQ&Aのポイント
  • 天理教の分教会や上級教会とのトラブルが起きた場合、どこに相談すればいいのでしょうか?以前に大教会に相談したことがありましたが、大教会からは分教会に関しては一切の管理責任はないとの回答がありました。もし問題がある場合は警察に行くように言われました。
  • 天理教でトラブルが発生した場合、相談先はどこになるのでしょうか?分教会や上級教会に問題がある場合、大教会に相談しても一切の責任を負わないと言われた経験があります。問題がある場合は警察に相談するしかないのでしょうか?
  • 天理教の教会とトラブルが生じた場合、どこに相談すればいいのでしょうか?分教会や上級教会に問題がある場合、大教会は一切関与しないとのことです。ですが、問題がある場合には警察に相談することが求められるのでしょうか?
回答を見る