TcpListenerについて への返答
投稿で使用できる特殊コードの説明。(別タブで開きます。)
以下の返答は逆順(新しい順)に並んでいます。
投稿者 kiku  (社会人)
投稿日時
2018/3/17 09:54:36
TcpListenerでも複数クライアントに対応できます。
すでにご案内している下記のサンプルも、そのような作りになっています。
http://nonsoft.la.coocan.jp/SoftSample/CS.NET/SampleTcpIpSvr.html
概要だけ説明しますと、
AcceptTcpClientの返り値は、TcpClientなのですが、
これは、TCP接続毎に作られます。
つまり、2つのクライアントから接続があった場合、
2つ作られることになるわけです。
2つできたらそれぞれを独立して処理していけば良いということです。
それぞれを独立させて処理するために、
スレッドなどを使っている感じです。
ご案内したサンプルは、まだサンプルレベルですが、
非常に良くできているので、良く解析し、理解されると良いかもです。
すでにご案内している下記のサンプルも、そのような作りになっています。
http://nonsoft.la.coocan.jp/SoftSample/CS.NET/SampleTcpIpSvr.html
概要だけ説明しますと、
AcceptTcpClientの返り値は、TcpClientなのですが、
これは、TCP接続毎に作られます。
つまり、2つのクライアントから接続があった場合、
2つ作られることになるわけです。
2つできたらそれぞれを独立して処理していけば良いということです。
それぞれを独立させて処理するために、
スレッドなどを使っている感じです。
ご案内したサンプルは、まだサンプルレベルですが、
非常に良くできているので、良く解析し、理解されると良いかもです。
投稿者 ポムNNN  (社会人)
投稿日時
2018/3/16 20:46:12
kiku様
完全に私の勘違いでした・・・。
もっと勉強いたします。
質問なのですが、複数台のクライアントを接続する場合は、TcpListenerクラスでも可能なのでしょうか?
より細かい設定ができるSocketクラスを使うべきなのでしょうか?
完全に私の勘違いでした・・・。
もっと勉強いたします。
質問なのですが、複数台のクライアントを接続する場合は、TcpListenerクラスでも可能なのでしょうか?
より細かい設定ができるSocketクラスを使うべきなのでしょうか?
投稿者 kiku  (社会人)
投稿日時
2018/3/14 09:15:19
Client と NetStreamの破棄のタイミングですが、
クライアントとの通信を終了したらになります。
では、通信が終了したらとはどういう条件かというと
どんなアプリケーションを作りたいかによって変わってきますが、
例えば下記が考えられます。
1.クライアントがデータ送信をする必要がなくなったため、
クライアントから接続を切断したとき。
2.サーバはクライアントとの通信を終了したいとき。
●上記1に対応
netstream.Readは、ブロックする命令で
受信できたら受信できたデータ数を返しますが
クライアントが接続を切断すると、負の値(うる覚え)を返します。
負の値だったら、クライアントは接続を切断しているため、
サーバはClient と NetStreamを破棄して、
AcceptTcpClientでクライアントからの新しい接続を待ちます。
●上記2の対応
Stop_Flgがtrueになったら、
サーバはClient と NetStreamを破棄して、
アプリケーションを終了します。
クライアントとの通信を終了したらになります。
では、通信が終了したらとはどういう条件かというと
どんなアプリケーションを作りたいかによって変わってきますが、
例えば下記が考えられます。
1.クライアントがデータ送信をする必要がなくなったため、
クライアントから接続を切断したとき。
2.サーバはクライアントとの通信を終了したいとき。
●上記1に対応
netstream.Readは、ブロックする命令で
受信できたら受信できたデータ数を返しますが
クライアントが接続を切断すると、負の値(うる覚え)を返します。
負の値だったら、クライアントは接続を切断しているため、
サーバはClient と NetStreamを破棄して、
AcceptTcpClientでクライアントからの新しい接続を待ちます。
●上記2の対応
Stop_Flgがtrueになったら、
サーバはClient と NetStreamを破棄して、
アプリケーションを終了します。
投稿者 ポムNNN  (社会人)
投稿日時
2018/3/13 23:12:53
kiku様 情報ありがとうございます。
現状としましては、いくつか疑問はありますが、目的通り動いている状況です。毎回違う値をクライアントからサーバに送って、値が同じことを確認できました。
>・サーバは、複数クライアントからの同時接続に対応していない。※1対1の通信であるならば問題ありません。
今回の1対1の通信用のアプリを作っています。いつかは複数台を受けることができるようにする予定です。
>・Sleepで待つのは良くないです。
過去の投稿にありました。勉強不足でした。ご指摘ありがとうございます。
> 13.サーバは、ClientとNetStream共に破棄していないため、クライアントからの2回目のデータ送信は受信できているが、サーバは、その受信データを読みだしていない。
についてですが、1回目の読み出し後、ClientとNetStreamを破棄してしまうと、2回目の読み出し前にAcceptTcpClient か それに代わる事をしなければないといけない気がするのですが、どうなのでしょうか?私の解釈間違いだったら、すみません。
クライントとサーバが接続しっぱなしでデータをやり取りする場合でも、読み込み終了の度に Closeするもんなのでしょうか?
なので Client と NetStreamのCloseはコメント扱いになっています・・・・。
他の部分は、前回の投稿と同じなので今回は、サーバ部分のみ記載しています。
Public Sub DoWork()
Dim server As TcpListener
Dim Client As TcpClient
Dim netstream As NetworkStream
server = Nothing
Stop_Flg = False
Try
Dim port As Integer = 9000
Dim localAddr As IPAddress = IPAddress.Parse("192.168.250.19")
server = New TcpListener(localAddr, port)
server.Start()
Invoke(New Action(Sub()
TextBox1.Text = "サーバー開始"
End Sub))
Client = server.AcceptTcpClient
While Stop_Flg <> True
Dim bytes(2) As Byte
netstream = Client.GetStream
Dim ReadSize As Integer = netstream.Read(bytes, 0, bytes.Length)
If ReadSize > 0 Then
For Each i In bytes
Console.Write(Chr(i))
Next
Console.Write(vbNewLine)
End If
End While
'netstream.Close()
'Client.Close()
Catch e As Exception
MsgBox(e.ToString)
Finally
server.Stop()
End Try
現状としましては、いくつか疑問はありますが、目的通り動いている状況です。毎回違う値をクライアントからサーバに送って、値が同じことを確認できました。
>・サーバは、複数クライアントからの同時接続に対応していない。※1対1の通信であるならば問題ありません。
今回の1対1の通信用のアプリを作っています。いつかは複数台を受けることができるようにする予定です。
>・Sleepで待つのは良くないです。
過去の投稿にありました。勉強不足でした。ご指摘ありがとうございます。
> 13.サーバは、ClientとNetStream共に破棄していないため、クライアントからの2回目のデータ送信は受信できているが、サーバは、その受信データを読みだしていない。
についてですが、1回目の読み出し後、ClientとNetStreamを破棄してしまうと、2回目の読み出し前にAcceptTcpClient か それに代わる事をしなければないといけない気がするのですが、どうなのでしょうか?私の解釈間違いだったら、すみません。
クライントとサーバが接続しっぱなしでデータをやり取りする場合でも、読み込み終了の度に Closeするもんなのでしょうか?
なので Client と NetStreamのCloseはコメント扱いになっています・・・・。
他の部分は、前回の投稿と同じなので今回は、サーバ部分のみ記載しています。
Public Sub DoWork()
Dim server As TcpListener
Dim Client As TcpClient
Dim netstream As NetworkStream
server = Nothing
Stop_Flg = False
Try
Dim port As Integer = 9000
Dim localAddr As IPAddress = IPAddress.Parse("192.168.250.19")
server = New TcpListener(localAddr, port)
server.Start()
Invoke(New Action(Sub()
TextBox1.Text = "サーバー開始"
End Sub))
Client = server.AcceptTcpClient
While Stop_Flg <> True
Dim bytes(2) As Byte
netstream = Client.GetStream
Dim ReadSize As Integer = netstream.Read(bytes, 0, bytes.Length)
If ReadSize > 0 Then
For Each i In bytes
Console.Write(Chr(i))
Next
Console.Write(vbNewLine)
End If
End While
'netstream.Close()
'Client.Close()
Catch e As Exception
MsgBox(e.ToString)
Finally
server.Stop()
End Try
投稿者 kiku  (社会人)
投稿日時
2018/3/13 09:49:27
現在のソースでは、下記のような動作をします。
1.サーバは、AcceptTcpClientメソッドでブロックして接続待機
2.クライアントは、接続要求
3.サーバは、クライアントから接続要求があると、
AcceptTcpClientメソッドが終了する。
4.クライアントは、接続完了を受け取る。
5.クライアントは、データ送信する。
6.サーバは、Sleepでデータ受信するまで待つ。
7.サーバは、ReadBytesで受信データを取得する。
8.サーバは、受信データを出力する。
9.サーバは、whileで処理が戻る。
10.サーバは、AcceptTcpClientメソッドでブロックして接続待機
11.クライアントは、2回目のデータ送信をする。
12.サーバは、接続待ちしているので、AcceptTcpClientで止まっている状態がつづく。
13.サーバは、ClientとNetStream共に破棄していないため、
クライアントからの2回目のデータ送信は受信できているが、
サーバは、その受信データを読みだしていない。
AcceptTcpClientで接続を待つのではなく、
2回目のデータ受信に備えて、
ReadBytesなどを実施する必要があります。
参考になるURLを張っておきます。
http://nonsoft.la.coocan.jp/SoftSample/CS.NET/SampleTcpIpSvr.html
ここまでが質問に対する答えになります。
そのほか懸念点。
・サーバは、複数クライアントからの同時接続に対応していない。
※1対1の通信であるならば問題ありません。
・Sleepで待つのは良くないです。
・Client、NetStreamは、disposeをもっているので使わなくなったら破棄しましょう。
1.サーバは、AcceptTcpClientメソッドでブロックして接続待機
2.クライアントは、接続要求
3.サーバは、クライアントから接続要求があると、
AcceptTcpClientメソッドが終了する。
4.クライアントは、接続完了を受け取る。
5.クライアントは、データ送信する。
6.サーバは、Sleepでデータ受信するまで待つ。
7.サーバは、ReadBytesで受信データを取得する。
8.サーバは、受信データを出力する。
9.サーバは、whileで処理が戻る。
10.サーバは、AcceptTcpClientメソッドでブロックして接続待機
11.クライアントは、2回目のデータ送信をする。
12.サーバは、接続待ちしているので、AcceptTcpClientで止まっている状態がつづく。
13.サーバは、ClientとNetStream共に破棄していないため、
クライアントからの2回目のデータ送信は受信できているが、
サーバは、その受信データを読みだしていない。
AcceptTcpClientで接続を待つのではなく、
2回目のデータ受信に備えて、
ReadBytesなどを実施する必要があります。
参考になるURLを張っておきます。
http://nonsoft.la.coocan.jp/SoftSample/CS.NET/SampleTcpIpSvr.html
ここまでが質問に対する答えになります。
そのほか懸念点。
・サーバは、複数クライアントからの同時接続に対応していない。
※1対1の通信であるならば問題ありません。
・Sleepで待つのは良くないです。
・Client、NetStreamは、disposeをもっているので使わなくなったら破棄しましょう。
投稿者 ポムNNN  (社会人)
投稿日時
2018/3/10 15:55:48
visual studio2015 で arduinoとパソコン をTCP/IPで通信するソフトを作っています。
arduinoがクライント、PCがサーバになるようにプログラムしています。
動作としましては、ボタン1でサーバを開始し、ボタン2でサーバ停止というプログラムになっています。
arduino側で 接続→送信→切断 のループのプログラムで動かすと上手くいくのですが、
初回接続後、接続しっぱなしで、arduinoからデータを送り続けるというパターンが上手くいきません。
下記プログラムの Client = server.AcceptTcpClient の部分が悪さをしている気がしました。
理由としては、arduinoからの接続要求が来ないのでサーバはダンマリ停止している状況だと判断しました。
使用するメソッドが間違っているのでしょうか?アドバイス頂けたらと思います。
Imports System.Net.Sockets
Imports System.Net
Public Class Form1
Private Stop_Flg As Boolean
Private server As TcpListener
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TextBox1.Text = ""
Task.Run(Sub() DoWork())
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Stop_Flg = True
End Sub
Public Sub DoWork()
server = Nothing
Stop_Flg = False
Try
Dim port As Integer = 9000
Dim localAddr As IPAddress = IPAddress.Parse("192.168.250.19")
server = New TcpListener(localAddr, port)
server.Start()
Invoke(New Action(Sub()
TextBox1.Text = "サーバー開始"
End Sub))
Dim data As String = Nothing
Dim Client As TcpClient = Nothing
Dim NetStream As NetworkStream
While Stop_Flg <> True
If server.Pending Then
While Stop_Flg <> True
Client = server.AcceptTcpClient
NetStream = Client.GetStream
Threading.Thread.Sleep(100) '相手からデータ到着までの待機時間
If NetStream.DataAvailable = True Then
Dim reader As New IO.BinaryReader(NetStream)
Dim bytes As Byte() = reader.ReadBytes(3)
For Each i In bytes
Console.Write(Chr(i)) ' "123" と表示される
Next
Console.Write(vbNewLine)
reader.Close()
End If
End While
Client.Close()
Else
Threading.Thread.Sleep(0)
End If
End While
Catch e As Exception
MsgBox(e.ToString)
Finally
server.Stop()
TextBox1.Text = "終了"
End Try
End Sub
End Class
arduinoがクライント、PCがサーバになるようにプログラムしています。
動作としましては、ボタン1でサーバを開始し、ボタン2でサーバ停止というプログラムになっています。
arduino側で 接続→送信→切断 のループのプログラムで動かすと上手くいくのですが、
初回接続後、接続しっぱなしで、arduinoからデータを送り続けるというパターンが上手くいきません。
下記プログラムの Client = server.AcceptTcpClient の部分が悪さをしている気がしました。
理由としては、arduinoからの接続要求が来ないのでサーバはダンマリ停止している状況だと判断しました。
使用するメソッドが間違っているのでしょうか?アドバイス頂けたらと思います。
Imports System.Net.Sockets
Imports System.Net
Public Class Form1
Private Stop_Flg As Boolean
Private server As TcpListener
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TextBox1.Text = ""
Task.Run(Sub() DoWork())
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Stop_Flg = True
End Sub
Public Sub DoWork()
server = Nothing
Stop_Flg = False
Try
Dim port As Integer = 9000
Dim localAddr As IPAddress = IPAddress.Parse("192.168.250.19")
server = New TcpListener(localAddr, port)
server.Start()
Invoke(New Action(Sub()
TextBox1.Text = "サーバー開始"
End Sub))
Dim data As String = Nothing
Dim Client As TcpClient = Nothing
Dim NetStream As NetworkStream
While Stop_Flg <> True
If server.Pending Then
While Stop_Flg <> True
Client = server.AcceptTcpClient
NetStream = Client.GetStream
Threading.Thread.Sleep(100) '相手からデータ到着までの待機時間
If NetStream.DataAvailable = True Then
Dim reader As New IO.BinaryReader(NetStream)
Dim bytes As Byte() = reader.ReadBytes(3)
For Each i In bytes
Console.Write(Chr(i)) ' "123" と表示される
Next
Console.Write(vbNewLine)
reader.Close()
End If
End While
Client.Close()
Else
Threading.Thread.Sleep(0)
End If
End While
Catch e As Exception
MsgBox(e.ToString)
Finally
server.Stop()
TextBox1.Text = "終了"
End Try
End Sub
End Class
頂いたサンプルをよく理解して複数台対応のサーバーを作ってみたいと思います。
色々アドバイス頂けて、大変助かりました。ありがとうございました。