2012-01-09 7 views
1

私はシンプルなHTTPクライアントを作成し、次のような問題に直面し、私はoffficialドキュメントからdo_recvことをcopypastedが、それは奇妙な方法で動作します:どのようgen_tcpを使用するには:recvの正確

do_recv(Sock, Bs) -> 
    case gen_tcp:recv(Sock, 0, ?TIMEOUT) of 
     {ok, B} -> 
      gen_tcp:shutdown(Sock, write), % <-- this appears to fix the problem! 
      do_recv(Sock, [Bs, B]); 
     {error, closed} -> 
      {ok, list_to_binary(Bs)} 
    end. 

チャットシーケンスは以下の通りです:

do_recv
{ok, S} = gen_tcp:connect(Ip, Port, [inet, binary, 
        {packet, 0}, 
        {active, false}, 
        {nodelay, true}, 
        {reuseaddr, true}], 2000), 
Req = io_lib:format("GET ~s HTTP/1.1\r\nHost: ~s\r\n\r\n", [Url, UrlHost]), 
ok = gen_tcp:send(S, list_to_binary(Req)) of 
do_recv(S, []); 

、最終呼び出しは時々期待どおりに動作し、サーバ resposeを返しますが、時にはそれは、サーバが独自にソケット を閉じていないので、私は推測する、ハングおよびタイムアウト。 タイムアウトの2番目のケースは、私が避けたい何か、というアイデアです どのようにその動作に対処するには?

UPD:

Iは、(コードサンプル内のコメントを参照してください)do_recv関数へgen_tcp:shutdown呼び出しを追加しました 、これは問題を解決するように見えるのです。質問は私が知っているかなりnoobishであり、解決策 はかなり推測のようである、多分誰かがここで何が起こるかを説明することができ、 彼らは通常この種の問題を解決する方法。

答えて

3

コードにはいくつか問題があります。

0を受け取ると、GET文字列の半分を得ることができます。または、カーネルがストリームをどのように処理するかによって、GET文字列全体を超えることができます。 TCPはストリーム指向であるため、十分なものが得られるまでソケットからデータを取得する必要があります。また、{error、timeout}トリガーで簡単に終わることができるので、その問題も処理する必要があります。それ以外の場合、期待どおりに動作しません。基本的には、GETを解析するのに十分なデータがあるまで、データを収集するループが必要です。すべてのデータを取得する前に、そのループでタイムアウトが発生します。

の線に沿って何か:

do_recv(Sock, Gathered) -> 
    case gen_tcp:recv(Sock, 0, ?TIMEOUT) of 
    {ok, Bin} -> 
     Remaining = try_decode(Sock, <<Gathered/binary, Bin/binary>>), 
     do_recv(Sock, Remaining); 
    {error, timeout} -> 
     do_recv(Sock, Remaining); 
    {error, Reason} -> 
     exit(Reason) 
    end. 

try_decode(Sock, Gathered) -> 
    case decode(Gathered) of 
     {ok, Data, Rest} -> 
     processor ! Data, 
     try_decode(Sock, Rest); 
     need_more_data -> 
     do_recv(Sock, Gathered) 
    end. 

はここで物事のカップルを想定し

  • デコード/ 1は、データをデコードしようとする関数であり、それがそうするように失敗し、より多くを要求するかもしれませんデータ。
  • プロセッサは、復号化されたメッセージを送信できるプロセスです。これは、単にデコードしたデータで何かを行う関数呼び出しでもあります。
+0

固定コードを提供できますか?それとも、複雑すぎるようですか? – Dfr

+0

衝突しましたが、テストされていません。 –

関連する問題