2009-08-10 29 views
6

私は自分のアプリケーション用に書いたアプリケーションを、私たちのWindows 2003サーバー(IIS 6.0を実行している)を通して私に送信するために社内に配布しました。小さなテキストメッセージは通過しますが、より多くのデータ(約20 KB)を含む大きなメッセージは通過しません。TCPクライアント接続

バイトバッファをTCPクライアントのバッファサイズに設定しました。私は自分のデータがサーバー上で受信されていることに気付きました。しかし、それは一度だけ受信ルーチンをループし、私の大きなファイルは常にバッファサイズのサイズ、または私たちのサーバー上の8 KBでした。言い換えれば、私のコードは、サーバーがソケット接続を閉じる前に、1つのループを通るだけです。

バッファ全体を埋めることに問題があると考えて、読み書きを1 KBに制限しようとしましたが、接続を閉じる前に1 KBを受け取ったサーバーがソケットを閉じるだけでした。

私はそれを見ることができるように、私はサーバーのエラーメッセージをクライアントに送り返します。私は、クライアントから受け取る特定のエラーメッセージは次のとおりです。私は私のサーバーアプリケーションを更新

“Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.”

基盤となるTCPソケットを使用して、この行で「キープアライブ」なるように:今

client.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true); 

、いつでも私がメッセージを送信しようとすると、クライアントはエラーを受信します。

“Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host.”

当社のネットワーク管理者は、彼がファイアウォールまたは社内サーバー上でブロックされた任意のポートを持っていないことを私に言いました。

エラーを調べると、人々がサーバーにtelnet接続しようとしていることを示唆している投稿が見つかりました。私はサーバーへのtelnetの指示を使用しましたが、私は応答の何を作るのか分かりません:

C:> telnet Welcome to Microsoft Telnet Client

Escape Character is ‘CTRL+]’

Microsoft Telnet> open cpapp 500 Connecting To cpapp…

これは私が得るすべてです。私は間違いなく、MicrosoftのTelnet画面は "Press any key to continue ..."に変わります。 - タイムアウトしたと思いますが、私のコードはどうにかして接続することができます。

25,80,8080を含むTelnetとコードで他のポートを試しました。Telnetがポート25を起動しますが、実行するためにどのポートに関係なく最初のループを読み込んでいるようです。ここで

は、クライアント上で動作する私のコードです:ここでは

int sendUsingTcp(string location) { 
    string result = string.Empty; 
    try { 
    using (FileStream fs = new FileStream(location, FileMode.Open, FileAccess.Read)) { 
     using (TcpClient client = new TcpClient(GetHostIP, CpAppDatabase.ServerPortNumber)) { 
     byte[] riteBuf = new byte[client.SendBufferSize]; 
     byte[] readBuf = new byte[client.ReceiveBufferSize]; 
     using (NetworkStream ns = client.GetStream()) { 
      if ((ns.CanRead == true) && (ns.CanWrite == true)) { 
      int len; 
      string AOK = string.Empty; 
      do { 
       len = fs.Read(riteBuf, 0, riteBuf.Length); 
       ns.Write(riteBuf, 0, len); 
       int nsRsvp = ns.Read(readBuf, 0, readBuf.Length); 
       AOK = Encoding.ASCII.GetString(readBuf, 0, nsRsvp); 
      } while ((len == riteBuf.Length) && (-1 < AOK.IndexOf("AOK"))); 
      result = AOK; 
      return 1; 
      } 
      return 0; 
     } 
     } 
    } 
    } catch (Exception err) { 
    Logger.LogError("Send()", err); 
    MessageBox.Show(err.Message, "Message Failed", MessageBoxButtons.OK, MessageBoxIcon.Hand, 0); 
    return -1; 
    } 
} 

は、サーバー上で実行されます私のコードです:

私のアプリケーションは、TCPクライアントからの読み込みを継続していないのはなぜ
SvrForm.Server = new TcpListener(IPAddress.Any, CpAppDatabase.ServerPortNumber); 

void Worker_Engine(object sender, DoWorkEventArgs e) { 
    BackgroundWorker worker = sender as BackgroundWorker; 
    string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), Application.CompanyName); 
    if (Directory.Exists(path) == false) Directory.CreateDirectory(path); 
    Thread.Sleep(0); 
    string eMsg = string.Empty; 
    try { 
    SvrForm.Server.Start(); 
    do { 
     using (TcpClient client = SvrForm.Server.AcceptTcpClient()) { // waits until data is avaiable 
     if (worker.CancellationPending == true) return; 
     client.Client.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true); 
     string location = Path.Combine(path, string.Format("Acp{0:yyyyMMddHHmmssff}.bin", DateTime.Now)); 
     byte[] buf = new byte[client.ReceiveBufferSize]; 
     try { 
      using (NetworkStream ns = client.GetStream()) { 
      if ((ns.CanRead == true) && (ns.CanWrite == true)) { 
       try { 
       int len; 
       byte[] AOK = Encoding.ASCII.GetBytes("AOK"); 
       using (FileStream fs = new FileStream(location, FileMode.Create, FileAccess.Write)) { 
        do { 
        len = ns.Read(buf, 0, client.ReceiveBufferSize); 
        fs.Write(buf, 0, len); 
        ns.Write(AOK, 0, AOK.Length); 
        } while ((0 < len) && (ns.DataAvailable == true)); 
       } 
       byte[] okBuf = Encoding.ASCII.GetBytes("Message Received on Server"); 
       ns.Write(okBuf, 0, okBuf.Length); 
       } catch (Exception err) { 
       Global.LogError("ServerForm.cs - Worker_Engine(DoWorkEvent)", err); 
       byte[] errBuf = Encoding.ASCII.GetBytes(err.Message); 
       ns.Write(errBuf, 0, errBuf.Length); 
       } 
      } 
      } 
     } 
     worker.ReportProgress(1, location); 
     } 
    } while (worker.CancellationPending == false); 
    } catch (SocketException) { 
    // See MSDN: Windows Sockets V2 API Error Code Documentation for detailed description of error code 
    e.Cancel = true; 
    } catch (Exception err) { 
    eMsg = "Worker General Error:\r\n" + err.Message; 
    e.Cancel = true; 
    e.Result = err; 
    } finally { 
    SvrForm.Server.Stop(); 
    } 
} 

?私が終了するまでソケットを開いたままにするよう指示するものを設定することを怠ったことがありますか? TCPクライアントが決して停止しないので、サーバーコードには例外が見られないので、エラーはないことがわかります。

私たちのネットワーク管理者はまだ仲間の学位を取得していないので、あなたが言っていることを理解していない可能性があるため、この問題を解決する方法について、 。

私はこのことについて長い間謝罪していますが、皆さんが私のやり方を知っていることを確認したいと思います。

ありがとうございます! 〜ジョー・

答えて

6

送信されたコンテンツの前にそのコンテンツの長さを挿入する必要があります。あなたのループは、データが送信されるときに実際にループが実行されているときに、ループが実行される前にすべてのデータが送信されることを前提としています。ワイヤで待機しているデータがないときにループが終了することがあります。一方、コンテンツは引き続きワイヤを介して送信されています。そのため、ループは1回だけ実行されます。

+0

冗談なし?今はそれが理にかなっていると思う。私は何かをサーバ上にセットアップする必要があると考え続けました。それは*ロット*に役立ちます!ありがとうございました! – jp2code

+0

どうすればいいですか? "送信されたコンテンツの前にそのコンテンツの長さ"送信されたコンテンツの長さはありませんか? –

+0

長さがわからない場合は、明らかに長さを電線に送信しないでください。 – Amy

1

私が正しくあなたのコードを読めば、あなたは基本的にCスタイルのための(申し訳ありません持っている - 私は、C#とよくないよ:私は正しいだ場合、それは、その後、

 
do 
{ 
    socket = accept(); 
    read(socket, buffer); 
}while(not_done); 

を、あなたはsimultaniously複数のアップロードを読みたい場合は

 
do 
{ 
    socket = accept(); 
    do { read(socket, buffer); not_done_reading=...; } while (not_done_reading); 
}while(not_done); 

:あなたが必要...もう少しそこにあなたはそれが順番に各アップロードを読んで、シリアライズさになりたい場合は、第二のループをお勧めします意味次のようなものが必要です:

 
do 
{ 
    socket = accept(); 
    if(!fork()) 
    { 
    do { read(socket, buffer); not_done_reading=...; } while (not_done_reading); 
    } 
}while(not_done); 
1

あなたのtelnetの例では、あなたが記述コードの動作に多少矛盾している - あなたは、サーバー上の何かを得ることができれば、「telnetの<ホスト名> <ポート番号>」は空白にあなたを取得する必要がありますかなり迅速に画面が表示されます(WindowsのCMDプロンプトで表示されます)。だから、これは最初の奇妙なことです。最高のデバッグはwireshark, thoughです。

コードワイズ、私はそれがサーバー上でこの内側のラインに問題があるかもしれないと思う:

...しばらく((0 < LEN)& &(ns.DataAvailable ==真));

何かを読んでいたときやデータがあるときにループしたいと言っています。

しかし、2番目のセグメントでまだサーバーに送信されていない可能性があります。したがって、まだデータがないため、このループから脱落しています。

何かを読んでいる間、および読み込みエラーがないうちにデータを受信するループを繰り返す必要があります。これにより、低速リンクでも確実にデータを受け取ることができます。

サイドノート:

私はあなたのプロトコルが要求 - 応答 - 要求 - 応答タイプです注意してください。これはLAN上でうまく動作しますが、将来的には往復時間の長いリンクで動作するようにする必要がある場合は、パフォーマンス上のボトルネックになります(MS SMBプロトコルはファイル転送やTFTPのように動作します) 。

(免責事項:私はC#で多くのコードを作成していないので、 "DataAvailable()"メソッドの解釈に間違っている可能性があります。

編集:おそらく私の答えはあなたのプロトコルに従って修正する必要があります。つまり、最初にファイルの長さを読み取ってからファイルを読む必要があります。あなたは完全にそれを設計しました。つまり、TCPでは、送信側でのwrite()操作の数が受信側でのread()操作の数と同じであるとは決して考えないでください。損失は​​ない、Nagle) - しかし、一般的なケースでは、それは当てはまりません。

関連する問題