2016-08-21 4 views
3

TcpListenerTcpClientが通信するときに、いくつかの機能がどのように共有されているかを正確に理解できません。TCP接続の両端で実行する必要があるアクション

(今の同期を無視するために)のは、次のコードが実行されるとしましょう:

サーバー:

Dim server As New TcpListener(localAddr, port) 
server.Start() 

Dim client As TcpClient = server.AcceptTcpClient() 

はクライアント:

Dim client As New TcpClient 
client.Connect(hostAddr, port) 

、接続が正常に確立されます。現在、サーバ側に1つ、クライアント側に1つのインスタンスが2つあります。ただし、同じネットワークストリームを共有するのはTcpClient.GetStream()です。

ちょっと混乱しています - server.AcceptTcpClient()を呼び出すと、クライアントはサーバーとそのすべてのプロパティをサーバーに渡しますか?

これ以降のTcpClientインスタンスの変更はどうなりますか?接続がシャットダウンしたとき、私は両側にこれを呼び出す:

client.GetStream.Close() 
client.Close() 

しかし、私はそれは、クライアントがすでに閉じていることを私に伝えますので、このコードは、最新のを実行し、クライアントにTcpClient.GetStream.Close()で例外を取得(これは場合に発生します上のコードは両側で完全には同期していません)。

.SendBufferSize.ReceiveBufferSizeのプロパティについてはどうなりますか?接続の両側にこれを設定する必要がありますか?

通信中にTcpClient/Listenerのクラスがどのくらい正確に動作しているのかについての説明で、誰かが私の混乱を解消できることを願っています - これまでのところ、正確に何が起こっているか説明するドキュメントは見つかりませんでした。

+0

「NetworkStream」と同じではありません。ストリームのそれぞれは、 'TcpClient'の基になる' Socket'にバインドされています。 - 'Send/ReceiveBufferSize'プロパティは単にあなたが送信または受信する方法を示しています。それらを変更することはそれほど役に立ちませんし、クライアント/サーバー上で異なることは実際には何にも影響しません。 –

+0

@VisualVincent送受信属性は 'server.AcceptTcpClient()'で送信されますか?私はあなたが意味することをあまり意味していないことをよく理解していません...確かに大きなファイルの交換を計画していたら、それらを増やしますか? – Shuri2060

+0

何も送信されません。唯一の同期プロパティは 'Connected'プロパティです。 '' BufferSize'プロパティは '' NetworkStream.Read/Write'を呼び出すたびにどれくらい送受信を期待するかの指標に過ぎません。引用[**ドキュメント**](https://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.sendbuffersize(v = vs.110).aspx):_ "SendBufferSizeプロパティは、NetworkStream.Writeメソッドへの各呼び出しで送信する予定のバイト数を取得または設定します。 "_ –

答えて

2

TCPプロトコルは、TcpClientが何であるかわかりません。これは.NETのコンセプトです。 TCPは.NETの概念をまったく参照しません。このため、ワイヤを介してオブジェクトが送信されることはありません。

送信されるのは、明示的に書き込むバイトだけです。

それぞれの側面には独自のオブジェクトがあります。両者は、TCP接続のハンドルのように動作する独自のTcpClientオブジェクトを使用します。

client.GetStream.Close() 
client.Close() 

これは適切なシャットダウンシーケンスではありません。最初の行は二番目と不完全に冗長です。 Closeは決して呼び出されるべきではありません。これを行う最善の方法は、クライアントをusingにラップすることです。 2番目に良い方法は、クライアントでDisposeに電話することです。 BCLのCloseメソッドは歴史的な事故であり、無視する必要があります。彼らはDisposeが私がこれまで見たすべてのケースで同じことをしています。

バッファサイズには手を触れないでください。カーネルが接続の最後にデータをバッファするために使用するメモリの量を制御します。カーネルはこれを単独で管理することができます。

また、コード内のバッファサイズも見ないでください。彼らは無意味です。また、DataAvailableプロパティを使用しないでください。false/0が返された場合、これはデータが読み取れないことを意味しないためです。

Connectedプロパティは、必ずしも両側で同期されません。ネットワークがダウンした場合、同期はできません。決してConnectedプロパティを見ないでください。それがtrueと言うならば、次のナノ秒はfalseとなります。したがって、そのプロパティに基づいて意思決定を行うことはできません。あなたは何かをテストする必要はありません。読み込み/書き込みだけを行い、中断して例外を処理します。

パケットに関しては、Writeのときにパケットを送信していません。 TCPには、境界のないバイトストリームがあります。カーネルはデータを内部的にパケット化します。データを特定のサイズに分割する必要はありません。 8Kなどのかなり大きなバッファサイズを使用してください(高速ネットワークではそれ以上)。書き込みサイズは、チャットが少ない(ナーグリングが有効になっていると仮定して)ことによって、CPU時間を節約することに関するものです。

+0

'を使うのが最善だと言うと、全てが1つのサブに含まれていないとできません。どうすればいいですか? 'Dispose'と呼ぶだけですか? – Shuri2060

+0

はい、Disposeを呼び出します。または、コードをすべて1つのサブになるように並べ替えます。このパターンを実行することもできます: 'void HandleConn(TcpClientクライアント){using(クライアント)...}'。 'using'は' new'を必要としません。 – usr

+0

ええええええええええええええええええええええええええええええええあれば - 問題は私がそれを送信/受信のための別の関数でラッパークラスを作ったことです。 – Shuri2060

関連する問題