3

SslStream を使用していくつかのソケット レイヤーに取り組んでいます。参照

リファレンスを使用して、単純なクライアントを実装しました。厄介な部分は、アプリケーションを実行するときに、サーバーがクライアントに応答していないように見えることです。

デバッグ画面に入っていくつかのブレークポイントを設定すると、この関数が無限ループしていることに気付きました。

static string ReadMessage(SslStream sslStream)
{
    // Read the  message sent by the server. 
    // The end of the message is signaled using the 
    // "<EOF>" marker.
    byte [] buffer = new byte[2048];
    StringBuilder messageData = new StringBuilder();
    int bytes = -1;
    do
    {
        bytes = sslStream.Read(buffer, 0, buffer.Length);

        // Use Decoder class to convert from bytes to UTF8 
        // in case a character spans two buffers.
        Decoder decoder = Encoding.UTF8.GetDecoder();
        char[] chars = new char[decoder.GetCharCount(buffer,0,bytes)];
        decoder.GetChars(buffer, 0, bytes, chars,0);
        messageData.Append (chars);
        // Check for EOF. 
        if (messageData.ToString().IndexOf("<EOF>") != -1)
        {
            break;
        }
    } while (bytes != 0); 

    return messageData.ToString();
}

さらなる調査により、ここで本当の犯罪者が指摘されました。

bytes = sslStream.Read(buffer, 0, buffer.Length);

どうやら、SslStream.Read()戻っていないようです。デバッグ画面で確認すると、応答がtilbyte[] bufferに書き込まれていることがわかります。関数はその仕事を終えましたが、まだ成功していませんか?!buffercrlf

この理由は何でしょうか?この問題を無視するには、どのような手順を踏む必要がありますか?

また、懐疑的な人のために:opensslサーバーが正常に動作しているかどうかを確認していましたが、サーバー側ではすべて問題ありません。

注:私はすでにSslStream.ReadTimeoutプロパティを認識しています。を発生させることでジョブをexception実行しますが、すべてのシナリオで正しい答えとは限りません。特に、while ループとバッファーを使用してのみ効率的に読み取ることができる大量のデータ ストリームでサーバーが応答している場合はそうです。

4

3 に答える 3

2

私は私と同じ問題に苦しんでいました.プログラムは無限ループでした.

以下の情報で解決しました

http,https プロトコルを使用している場合は? ヘッダーに「接続: 閉じる\r\n」を追加します

HTTP標準記事

14.10 接続

Connection general-header フィールドを使用すると、送信者は、その特定の接続に必要なオプションを指定できます。また、プロキシによってそれ以上の接続を介して通信してはなりません。

Connection ヘッダーの文法は次のとおりです。

   Connection = "Connection" ":" 1#(connection-token)
   connection-token  = token

HTTP/1.1 プロキシは、メッセージが転送される前に Connection ヘッダー フィールドを解析する必要があり、このフィールドの各接続トークンについて、接続トークンと同じ名前のヘッダー フィールドをメッセージから削除する必要があります。接続オプションは、対応する追加ヘッダー フィールドではなく、接続ヘッダー フィールドに接続トークンが存在することによって通知されます。これは、その接続オプションに関連付けられたパラメーターがない場合、追加ヘッダー フィールドが送信されない可能性があるためです。

Connection ヘッダーにリストされているメッセージ ヘッダーには、Cache-Control などのエンドツーエンド ヘッダーを含めてはなりません。

HTTP/1.1 は、応答の完了後に接続が閉じられることを送信者が通知するための "close" 接続オプションを定義します。例えば、

   **Connection: close**

要求または応答ヘッダー フィールドのいずれかで、現在の要求/応答が完了した後、接続が「永続的」(セクション 8.1) と見なされるべきではないことを示します。

永続的な接続をサポートしない HTTP/1.1 アプリケーションは、すべてのメッセージに「閉じる」接続オプションを含める必要があります。

接続ヘッダーを含む HTTP/1.0 (または下位バージョン) メッセージを受信するシステムは、このフィールドの接続トークンごとに、接続と同じ名前のメッセージからヘッダー フィールドを削除して無視する必要があります。トークン。これにより、HTTP/1.1 より前のプロキシによるそのようなヘッダー フィールドの誤った転送から保護されます。セクション 19.6.2 を参照してください。

于 2015-02-01T00:35:05.827 に答える
1

接続がまだ開いていて、サーバーが書き込みを行っていない場合は、<EOF>「ハング」しているだけです。さらなるデータを待っています。これ以上データが来ないことを知る唯一の方法は、サーバーが接続を閉じていることです。

サーバーが実際に送信したすべてのデータを読み取ることができましたか? 返されない呼び出しのmessageDataの反復ではどのように見えますか?

于 2012-08-28T14:43:20.147 に答える
-2

しばらく考えた後、回避策を見つけました。

sslStream.ReadTimeout = 100; //How much time does it takes for a processor to read and write 2048bytes to the buffer?

タイムアウトを使用する必要があり、他に何も機能していないようでした。例外を処理するように Reader を変更しました。

static string ReadMessage(SslStream sslStream)
{
    // Read the  message sent by the server.
    // The end of the message is signaled using the
    // "<EOF>" marker.
    byte[] buffer = new byte[2048];
    StringBuilder messageData = new StringBuilder();
    int bytes = -1;

    do
    {
        try
        {
            bytes = sslStream.Read(buffer, 0, buffer.Length);

        }
        catch (Exception ex)
        {
        }
        // Use Decoder class to convert from bytes to UTF8
        // in case a character spans two buffers.
        Decoder decoder = Encoding.ASCII.GetDecoder();
        char[] chars = new char[decoder.GetCharCount(buffer, 0, bytes)];
        decoder.GetChars(buffer, 0, bytes, chars, 0);
        messageData.Append(chars);
        // Check for EOF.
        if (messageData.ToString().IndexOf("\r\n") != -1)
        {
            break;
        }

    }
    while (bytes != -1);



    return messageData.ToString();
}

これは機能しますが、それが良い答えであるとは限りません。誰かがより良い答えを提供できれば、それは素晴らしいことです。

于 2012-08-29T16:20:30.167 に答える