2016-04-29 10 views
2

私はC#で単純なクライアントとサーバーを持っています。目標は、クライアントがXML文書をサーバーに送信し、サーバーが別のXML文書で応答する必要があることです。 XmlDocument.Load(NetworkStream)で入力/要求XMLを受信しようとすると、サーバーがブロックされています。NetworkStreamからXMLを読み込むときにサーバーがブロックされるのはなぜですか?

サーバー:

 TcpListener t = new TcpListener(IPAddress.Any, 4444); 
     t.Start(); 
     TcpClient c = t.AcceptTcpClient(); 
     NetworkStream s = c.GetStream(); 
     XmlDocument req = new XmlDocument(); 
     req.Load(s); 

     string respString = "<response><data>17</data></response>"; 
     XmlDocument resp = new XmlDocument(); 
     resp.LoadXml(respString); 
     resp.Save(s); 

クライアント:

 TcpClient t = new TcpClient("localhost", 4444); 
     NetworkStream s = t.GetStream(); 

     string reqStr = "<request><parameters><param>7</param><param>15</param></parameters></request>"; 
     XmlDocument req = new XmlDocument(); 
     req.LoadXml(reqStr); 

     req.Save(s); 

     XmlDocument resp = new XmlDocument(); 
     resp.Load(s); 

     Console.WriteLine(resp.OuterXml); 

それがストリームに要求XmlDocumentオブジェクトを保存した後、私はクライアントに)(フラッシュを追加しようとしたが、それは助けていないようでした。もともと私は、サーバーがクライアントからのすべての入力をMemoryStreamに読み込ませようとしましたが、その後、すべての入力が切断されずに実行されたことをサーバーに示す方法がないことが判明しました。その入力を読んでください。

netcatを使ってファイルからサーバにXML入力を送信できますが、すべて正常に動作します。これは、サーバーでXmlDocument.Load(NetworkStream)を使用するか、すべての入力をMemoryStreamに読み込むかどうかに関係なく機能します。このケースでnetcatが私のC#クライアントでやっていないことは何ですか、そしてC#ではどのようにしますか?私はこれについて別のことをするべきですか?

+0

ファイアウォールはどうですか? – qub1n

+0

ファイアウォールやウイルスチェッカーがポート番号をブロックしているなど、ストリームがブロックされている理由はたくさんあります。 IEウェブブラウザを使ってxmlを手動でダウンロードできるかどうかを最初に確認します。できる場合は、ファイアウォールの問題ではありません。その後、wiresharkやfiddleのようなスニファを使用して、IEのダウンロードをキャプチャし、結果をC#アプリケーションと比較します。通常、問題はIEの結果と一致するように変更する必要があるC#アプリケーションのhttpヘッダーです。 – jdweng

+0

ファイアウォールやネットワークの問題ではありません。同じマシンのnetcatが必要な入力を送信できます。 IEが私のサーバーにXMLリクエストを送信しないので、IEでこのシナリオをテストする方法がわかりません。 – skiphoppy

答えて

5

Tcp接続は双方向であり、残りの半分を開いたまま半分を閉じることができます。この場合、すべてのデータを送信した後、クライアントからサーバーの半分を閉じることができます。あなたはこのようなあなたの例のためにそれを行うことができます。

TcpClient t = new TcpClient("localhost", 4444); 
NetworkStream s = t.GetStream(); 
string reqStr = "<request><parameters><param>7</param><param>15</param></parameters></request>"; 
XmlDocument req = new XmlDocument(); 
req.LoadXml(reqStr); 
req.Save(s); 
// important line here! shutdown "send" half of the socket connection. 
t.Client.Shutdown(SocketShutdown.Send); 
XmlDocument resp = new XmlDocument(); 
resp.Load(s); 
Console.WriteLine(resp.OuterXml); 

あなたはすべてのデータ送信された後、サーバーの側でネットワークストリームを設けることを忘れないでください:実際に

TcpListener t = new TcpListener(IPAddress.Loopback, 4444); 
t.Start(); 
TcpClient c = t.AcceptTcpClient(); 
using (NetworkStream s = c.GetStream()) { 
    XmlDocument req = new XmlDocument(); 
    req.Load(s);     
    Console.WriteLine("Got request: {0}", req.OuterXml); 
    string respString = "<response><data>17</data></response>"; 
    XmlDocument resp = new XmlDocument(); 
    resp.LoadXml(respString); 
    resp.Save(s); 
} 

を全通信は単一の要求が続いている場合単一の応答 - tcpよりもカスタムプロトコルの代わりにこの手法を使用できます(タイムアウトを使用し、ストリームとTCPクライアントを適切に処分することを忘れないでください)。

それ以外の場合、ネットワークストリームはクライアントとサーバーの間のオープンな接続の一種であることに注意してください。明示的な「終了」はありません。 XmlDocument.Loadを実行しているとき、可能な限り(0バイトの読み込みでReadが返るまで)読み込まれますので、あなたの場合はブロックされます。あなた自身がメッセージ境界を定義できるように、あなた自身のプロトコルをtcpよりも定義しなければなりません。最初の4バイトは、次のメッセージの長さを定義します。したがって、最初の4バイトを読み取ってから、その長さに達するかタイムアウトが発生するまで読み取ります。

+0

@skiphoppyアップデートを見ると、あなたの質問にもっと完全に答えてくれると思います。 – Evk

+0

ありがとう、@エヴァーク、私はClient.Shutdown(SocketShutdown.Send)が私が行方不明になっているかもしれないと思う。私はシャットダウン()を昨日見つけましたが、片方だけをシャットダウンするように指示するパラメータがあることに気づいていませんでした。 – skiphoppy

+0

ラット。 Client.Shutdown(SocketShutdown.Send)を試してみるともう少し時間がかかりますが、クライアントがサーバーの送信内容を読み込もうとすると、「トランスポート接続からデータを読み取ることができません:既存の接続は強制的にリモートホストによって閉じられています。両側のような音が止まった。 – skiphoppy