ReadLine 似乎在轮流连接和发送,导致问题
ReadLine seems to be taking turns around connections and sends, causing problems
我正在处理多个连接的原始模式连接中创建服务器聊天功能,以便在我的大型应用程序中讨论调试消息。它使用 StreamReader
的列表来填充连接的读取流,以允许人们在调试器网络控制台上编写文本消息。
我正在为应用程序的下一个版本实现聊天功能,因此连接的客户端可以在应用程序 运行.
时就打印的调试消息进行聊天和评论
我在 .NET Framework 4.7.2 上使用 Visual Studio 2019。当我完成聊天功能的编写时,似乎当第一个用户连接到调试器时,聊天看起来很好,因为每次他们按 Enter 时,都会出现关于它的调试消息,就像:
9/9/2019 5:57 PM (RemoteDebugger.vb:55): Debug device 192.168.1.105 connected.
Test
9/9/2019 5:57 PM (RemoteDebugger.vb:70): 192.168.1.105> Test
Test 2
9/9/2019 5:57 PM (RemoteDebugger.vb:70): 192.168.1.105> Test 2
Debugger test
9/9/2019 5:57 PM (RemoteDebugger.vb:70): 192.168.1.105> Debugger test
但是,随着时间的流逝,用户将能够很好地连接到调试器,但是聊天功能似乎在第一个用户交谈之前对其他用户不起作用,所以它的行为就像他们正在接受轮流发布他们的消息。
另外,当第二个用户说了一次或太多,而第一个用户重复回车时,第二个用户的消息似乎是在第二次按下回车或第二次发送消息后出现的。
进一步调试,我发现ReadLine
好像是阻塞了,本该不打印消息就继续的,下一个连接去另一个StreamReader
让消息通过正确。这意味着当我在 ReadLine
断点后恢复程序时,它不会继续,直到检测到下一条消息,如果第二个用户试图说话,断点不会触发,直到第一个用户说话.
为了清楚起见,这里是两个连接的输出:
- 第一次连接:
9/9/2019 5:57 PM (RemoteDebugger.vb:55): Debug device 127.0.0.1 connected.
Hello
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105> Hello
Test
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105> Test
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Hello
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Snja
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Sinmue
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Sona
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Mnjad
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> kodkw
fds
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105> fds
- 第二次连接:
9/9/2019 5:57 PM (RemoteDebugger.vb:55): Debug device 127.0.0.1 connected.
Hello
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105> Hello
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105> Test
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Hello
Snja
Sinmue
Sona
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Snja
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Sinmue
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Sona
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
Mnjad
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Mnjad
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
kodkw
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> kodkw
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105> fds
在一个大项目中作为聊天功能的一部分的代码如下:
Public DebugPort As Integer = 3014
Public RDebugClient As Socket
Public DebugTCP As TcpListener
Public DebugDevices As New List(Of Socket)
Public dbgConns As New List(Of StreamWriter)
Public dbgChats As New Dictionary(Of StreamReader, String)
Sub StartRDebugThread()
If DebugMode Then
Dim RDebugThread As New Thread(AddressOf StartRDebugger) With {.IsBackground = True}
RDebugThread.Start()
End If
End Sub
Sub StartRDebugger()
'Listen to a current IP address
DebugTCP = New TcpListener(New IPAddress({0, 0, 0, 0}), DebugPort)
DebugTCP.Start()
Dim RStream As New Thread(AddressOf ReadAndBroadcastAsync)
RStream.Start()
W(DoTranslation("Debug listening on all addresses using port {0}.", currentLang), True, ColTypes.Neutral, DebugPort)
While Not RebootRequested
Try
Dim RDebugStream As NetworkStream
Dim RDebugClient As Socket
If DebugTCP.Pending Then
RDebugClient = DebugTCP.AcceptSocket
RDebugStream = New NetworkStream(RDebugClient)
dbgConns.Add(New StreamWriter(RDebugStream) With {.AutoFlush = True})
dbgChats.Add(New StreamReader(RDebugStream), RDebugClient.RemoteEndPoint.ToString.Remove(RDebugClient.RemoteEndPoint.ToString.IndexOf(":")))
DebugDevices.Add(RDebugClient)
Wdbg("Debug device {0} connected.", RDebugClient.RemoteEndPoint.ToString.Remove(RDebugClient.RemoteEndPoint.ToString.IndexOf(":")))
End If
Catch ex As Exception
W(DoTranslation("Error in connection: {0}", currentLang), True, ColTypes.Neutral, ex.Message)
End Try
End While
DebugTCP.Stop()
dbgConns.Clear()
Thread.CurrentThread.Abort()
End Sub
Sub ReadAndBroadcastAsync()
While True
For i As Integer = 0 To dbgChats.Count - 1
Dim msg As String = dbgChats.Keys(i).ReadLine()
Wdbg("{0}> {1}", dbgChats.Values(i), msg)
Next
End While
End Sub
我能做什么?我还尝试了 ReadLineAsync
函数来等待它,但它没有任何改变。如果您需要任何进一步的信息,我会提供。
我终于解决了似乎轮流聊天的问题,方法是在阅读前将读取超时设置为 10 毫秒。
streamnet.ReadTimeout = 10 'Seems to have fixed it
当reader超时时,它会产生一个异常,SocketErrorCode是ReadTimeout,所以我用Try..Catch块包围了Read及其周围的所有函数,组成:
Try
streamnet.Read(buff, 0, 65536)
Dim msg As String = Text.Encoding.Default.GetString(buff)
msg = msg.Replace(vbCr, vbNullChar) 'Remove all instances of vbCr (macOS newlines) } Windows hosts are affected, too, because it uses
msg = msg.Replace(vbLf, vbNullChar) 'Remove all instances of vbLf (Linux newlines) } vbCrLf, which means (vbCr + vbLf)
If Not msg.StartsWith(vbNullChar) Then Wdbg("{0}> {1}", ip, msg) 'Don't post message if it starts with a null character.
Catch ex As Exception
Dim SE As SocketException = CType(ex.InnerException, SocketException)
If Not IsNothing(SE) And Not SE.SocketErrorCode = SocketError.TimedOut Then
Wdbg("Error from host {0}: {1}", ip, SE.SocketErrorCode.ToString)
End If
End Try
因此,如果您打算在原始文本模式下制作一个没有客户端 运行 的聊天服务器,请使用它。
我正在处理多个连接的原始模式连接中创建服务器聊天功能,以便在我的大型应用程序中讨论调试消息。它使用 StreamReader
的列表来填充连接的读取流,以允许人们在调试器网络控制台上编写文本消息。
我正在为应用程序的下一个版本实现聊天功能,因此连接的客户端可以在应用程序 运行.
时就打印的调试消息进行聊天和评论我在 .NET Framework 4.7.2 上使用 Visual Studio 2019。当我完成聊天功能的编写时,似乎当第一个用户连接到调试器时,聊天看起来很好,因为每次他们按 Enter 时,都会出现关于它的调试消息,就像:
9/9/2019 5:57 PM (RemoteDebugger.vb:55): Debug device 192.168.1.105 connected.
Test
9/9/2019 5:57 PM (RemoteDebugger.vb:70): 192.168.1.105> Test
Test 2
9/9/2019 5:57 PM (RemoteDebugger.vb:70): 192.168.1.105> Test 2
Debugger test
9/9/2019 5:57 PM (RemoteDebugger.vb:70): 192.168.1.105> Debugger test
但是,随着时间的流逝,用户将能够很好地连接到调试器,但是聊天功能似乎在第一个用户交谈之前对其他用户不起作用,所以它的行为就像他们正在接受轮流发布他们的消息。
另外,当第二个用户说了一次或太多,而第一个用户重复回车时,第二个用户的消息似乎是在第二次按下回车或第二次发送消息后出现的。
进一步调试,我发现ReadLine
好像是阻塞了,本该不打印消息就继续的,下一个连接去另一个StreamReader
让消息通过正确。这意味着当我在 ReadLine
断点后恢复程序时,它不会继续,直到检测到下一条消息,如果第二个用户试图说话,断点不会触发,直到第一个用户说话.
为了清楚起见,这里是两个连接的输出:
- 第一次连接:
9/9/2019 5:57 PM (RemoteDebugger.vb:55): Debug device 127.0.0.1 connected.
Hello
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105> Hello
Test
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105> Test
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Hello
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Snja
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Sinmue
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Sona
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Mnjad
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> kodkw
fds
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105> fds
- 第二次连接:
9/9/2019 5:57 PM (RemoteDebugger.vb:55): Debug device 127.0.0.1 connected.
Hello
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105> Hello
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105> Test
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Hello
Snja
Sinmue
Sona
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Snja
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Sinmue
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Sona
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
Mnjad
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> Mnjad
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105>
kodkw
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 127.0.0.1> kodkw
9/9/2019 5:58 PM (RemoteDebugger.vb:70): 192.168.1.105> fds
在一个大项目中作为聊天功能的一部分的代码如下:
Public DebugPort As Integer = 3014
Public RDebugClient As Socket
Public DebugTCP As TcpListener
Public DebugDevices As New List(Of Socket)
Public dbgConns As New List(Of StreamWriter)
Public dbgChats As New Dictionary(Of StreamReader, String)
Sub StartRDebugThread()
If DebugMode Then
Dim RDebugThread As New Thread(AddressOf StartRDebugger) With {.IsBackground = True}
RDebugThread.Start()
End If
End Sub
Sub StartRDebugger()
'Listen to a current IP address
DebugTCP = New TcpListener(New IPAddress({0, 0, 0, 0}), DebugPort)
DebugTCP.Start()
Dim RStream As New Thread(AddressOf ReadAndBroadcastAsync)
RStream.Start()
W(DoTranslation("Debug listening on all addresses using port {0}.", currentLang), True, ColTypes.Neutral, DebugPort)
While Not RebootRequested
Try
Dim RDebugStream As NetworkStream
Dim RDebugClient As Socket
If DebugTCP.Pending Then
RDebugClient = DebugTCP.AcceptSocket
RDebugStream = New NetworkStream(RDebugClient)
dbgConns.Add(New StreamWriter(RDebugStream) With {.AutoFlush = True})
dbgChats.Add(New StreamReader(RDebugStream), RDebugClient.RemoteEndPoint.ToString.Remove(RDebugClient.RemoteEndPoint.ToString.IndexOf(":")))
DebugDevices.Add(RDebugClient)
Wdbg("Debug device {0} connected.", RDebugClient.RemoteEndPoint.ToString.Remove(RDebugClient.RemoteEndPoint.ToString.IndexOf(":")))
End If
Catch ex As Exception
W(DoTranslation("Error in connection: {0}", currentLang), True, ColTypes.Neutral, ex.Message)
End Try
End While
DebugTCP.Stop()
dbgConns.Clear()
Thread.CurrentThread.Abort()
End Sub
Sub ReadAndBroadcastAsync()
While True
For i As Integer = 0 To dbgChats.Count - 1
Dim msg As String = dbgChats.Keys(i).ReadLine()
Wdbg("{0}> {1}", dbgChats.Values(i), msg)
Next
End While
End Sub
我能做什么?我还尝试了 ReadLineAsync
函数来等待它,但它没有任何改变。如果您需要任何进一步的信息,我会提供。
我终于解决了似乎轮流聊天的问题,方法是在阅读前将读取超时设置为 10 毫秒。
streamnet.ReadTimeout = 10 'Seems to have fixed it
当reader超时时,它会产生一个异常,SocketErrorCode是ReadTimeout,所以我用Try..Catch块包围了Read及其周围的所有函数,组成:
Try
streamnet.Read(buff, 0, 65536)
Dim msg As String = Text.Encoding.Default.GetString(buff)
msg = msg.Replace(vbCr, vbNullChar) 'Remove all instances of vbCr (macOS newlines) } Windows hosts are affected, too, because it uses
msg = msg.Replace(vbLf, vbNullChar) 'Remove all instances of vbLf (Linux newlines) } vbCrLf, which means (vbCr + vbLf)
If Not msg.StartsWith(vbNullChar) Then Wdbg("{0}> {1}", ip, msg) 'Don't post message if it starts with a null character.
Catch ex As Exception
Dim SE As SocketException = CType(ex.InnerException, SocketException)
If Not IsNothing(SE) And Not SE.SocketErrorCode = SocketError.TimedOut Then
Wdbg("Error from host {0}: {1}", ip, SE.SocketErrorCode.ToString)
End If
End Try
因此,如果您打算在原始文本模式下制作一个没有客户端 运行 的聊天服务器,请使用它。