4

私は、Webサービスを使用していくつかのイベントをプッシュするクライアントで作業しています.Webサービスは、クライアントがサブスクライブコマンドをPOSTすると、関心のあるイベントを送り返し、クライアントは接続を維持します。

コマンドを POST すると、サービスはこれらのヘッダーを含む最初の応答で (すぐに) 応答します。

Keep-Alive: timeout=5, max=98
Connection: Keep-Alive
Transfer-Encoding: chunked

その後、タイムアウトするまで接続を開いたままにします (30 秒後、クライアントがキープアライブ データを送信しない場合)。

これは、POST + 応答を読み取る必要がある + endOFStream まで接続を開いたままにしておくことが混在しているため、HttpWebRequest を BeginGetRequestStream (POST へ) および BeginGetResponse と共に使用して、応答を読み取って処理する必要があるようです。

私の問題は、AllowReadStreamBuffering が false に設定されているにもかかわらず、入力ストリームがサーバー/サービスによって実際に閉じられるまで (30 秒後)、BeginGetResponse コールバックが呼び出されないことです。

ドキュメントには、AllowReadStreamBuffering について次のように書かれています。

AllowReadStreamBuffering プロパティは、BeginGetResponse メソッドからのコールバックが呼び出されるタイミングに影響します。AllowReadStreamBuffering プロパティが true の場合、ストリーム全体がメモリにダウンロードされると、コールバックが発生します。AllowReadStreamBuffering プロパティが false の場合、すべてのデータが到着する前に、ストリームが読み取り可能になるとすぐにコールバックが発生します。

AllowReadStreamBuffering が何に設定されていても、HttpWebRequest はバッファーがいっぱいになるまで BeginGetResponse を呼び出さないといういくつかの提案を見てきましたが、ドキュメントでそれについて何も見つけることができませんでした。

このバッファリング動作を制御する方法や、この種の Web サービスを扱うときに試してみるべき別のアプローチへの提案について、誰かが考えていますか?

私が現在使用しているコードの関連スニペットは、次のようになります。

public void open()
{
    string url = "http://funplaceontheinternet/webservice";

    HttpWebRequest request = WebRequest.CreateHttp(url);
    request.Method = "POST";
    request.Credentials = new NetworkCredential("username", "password");
    request.CookieContainer = new CookieContainer();
    request.AllowReadStreamBuffering = false;         
    request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
}

void GetRequestStreamCallback(IAsyncResult result)
{
    Debug.WriteLine("open.GetRequestStreamCallback");

    HttpWebRequest webRequest = (HttpWebRequest)result.AsyncState;
    // End the stream request operation
    Stream postStream = webRequest.EndGetRequestStream(result);

    // Create the post data
    byte[] byteArray = Encoding.UTF8.GetBytes(_xmlEncodedSubscribeCommand);

    // Add the post data to the web request
    postStream.Write(byteArray, 0, byteArray.Length);
    postStream.Close();

    // Start the web request
    webRequest.BeginGetResponse(new AsyncCallback(BeginGetResponseCallback), webRequest);
}

void BeginGetResponseCallback(IAsyncResult result)
{
    HttpWebRequest request = (HttpWebRequest)result.AsyncState;
    HttpWebResponse response = null;
    if (request != null)
        response = (HttpWebResponse)request.EndGetResponse(result);
    else
        Debug.WriteLine("request==null :-(");
    if (response != null)
    {
        using (var reader = new StreamReader(response.GetResponseStream()))
        {
            while (!reader.EndOfStream)
            {
                string line = reader.ReadLine();
                Debug.WriteLine("BeginGetResponseCallback - received: " + line);
            }
            Debug.WriteLine("BeginGetResponseCallback - reader.EndOfStream");
        }
    }
    else
        Debug.WriteLine("response==null :-(");
}
4

1 に答える 1

0

このサービスは Web サービスであると述べましたが、どのプラットフォームかは言及していません。これが「通常の」Web サービスである場合、XML がトランスポート形式であると想定します。

もしそうなら、問題はこのスタイルのコミュニケーションが実際にはストリーミングに向いていないことにあるのではないかと思います. サーバー側の Web サービス インフラストラクチャは、すべてのデータが利用可能になるまで、SOAP エンベロープとペイロードを作成しない可能性があります。このようにストリーミングしたい場合は、Web サービスではなく、サーバー側で何らかのカスタム サービスを使用する方がよい場合があります。

サーバーが実際に応答をストリーミングしていることを確実に知っていますか? (例えば、wireshark のようなもので確認されましたか?)

本当に Web サービスを使用したい場合は、最初のイベントが利用可能になったときにリクエストを完了し、タイムアウトを待たないことをお勧めします。これでも、あなたが取得しようとしていると思われるレイテンシーの削減が達成されます。

于 2013-07-13T09:09:16.977 に答える