0

我正在构建一个可以与游戏服务器通信和发送命令的应用程序。在游戏世界中,我们称之为远程控制台的“rcon”,但实际上它只是一个 telnet 会话。验证成功后,可以向服务器发出文本命令,并将文本响应发送回客户端。

服务器管理员/所有者经常运行多个游戏服务器,每个服务器都有自己独特的 IP 地址、端口和密码。我希望我的应用程序循环遍历服务器的列表/数组/数据表/字典(或任何最好的方法),连接并验证每个服务器,然后以某种方式存储该连接,以便将来可以将命令发送给它(没有必须重新连接和验证)

下面是我拥有的适用于单个服务器的代码。我将 TcpClient(client) 和 NetworkStream(stm) 存储为全局对象,使连接/会话保持对服务器开放。由于每台服务器都有自己的 TcpClient 和 NetworkStream,对我来说,使用多台服务器执行此操作的最佳方法是什么?

我有什么方法可以将每个 TcpClient(client) 和 NetworkStream(stm) 存储在数组、字典或其他东西中吗?我完全不知道如何处理这个问题。

Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
Imports System.Security.Cryptography
Imports System.IO

Public Class Form1

    Public client As TcpClient
    Public stm As NetworkStream

    Sub SendCmd(cmd As String)
        Dim data
        If cmd.Trim = "" Then
            data = Encoding.GetEncoding(1252).GetBytes(cmd)
        Else
            data = Encoding.GetEncoding(1252).GetBytes(cmd & vbCrLf)
        End If

        stm.Write(data, 0, data.Length)
        Dim resp As Byte() = New Byte(512) {}
        Dim memStream = New MemoryStream()
        Thread.Sleep(500)
        Dim bytes As Integer = 0
        If stm.DataAvailable Then
            Do
                Thread.Sleep(10)
                bytes = stm.Read(resp, 0, resp.Length)

                memStream.Write(resp, 0, bytes)
            Loop While stm.DataAvailable
            Dim responsedata As String = Encoding.GetEncoding(1252).GetString(memStream.ToArray())

            If responsedata.Contains("### Digest seed: ") Then
                'The server is asking for authentication: Login to the server now
                Authenticate(responsedata)
            End If
            OutputRTB.Text &= responsedata
        End If
        memStream.Close()
    End Sub

    Sub GetPlayerList()
        If stm.CanRead Then
            Dim data = Encoding.GetEncoding(1252).GetBytes("bf2cc pl" & vbCrLf)


            Dim PlayerDT As New DataTable
            PlayerDT.Columns.Add("PlayerSlot", GetType(Integer))
            PlayerDT.Columns.Add("HeroName", GetType(String))
            PlayerDT.Columns.Add("Score", GetType(String))
            PlayerDT.Columns.Add("HeroID", GetType(String))
            PlayerDT.Columns.Add("PlayerID", GetType(String))
            PlayerDT.Columns.Add("Level", GetType(Integer))
            PlayerDT.Columns.Add("Class", GetType(String))
            PlayerDT.Columns.Add("Ping", GetType(Integer))


            stm.Write(data, 0, data.Length)
            Dim resp As Byte() = New Byte(512) {}
            Dim memStream = New MemoryStream()
            Thread.Sleep(500)
            Dim bytes As Integer = 0
            If stm.DataAvailable Then
                Do
                    Thread.Sleep(10)
                    bytes = stm.Read(resp, 0, resp.Length)

                    memStream.Write(resp, 0, bytes)
                Loop While stm.DataAvailable
                Dim responsedata As String = Encoding.GetEncoding(1252).GetString(memStream.ToArray())

                If responsedata.Contains("### Digest seed: ") Then
                    'Login to the server
                    Authenticate(responsedata)
                End If
                OutputRTB.Text = responsedata.Replace(vbTab, "^")


                Dim Rows() As String = responsedata.Split(Environment.NewLine)
                For i = 0 To Rows.Length - 1
                    Dim Cols() As String = Rows(i).Split(vbTab)
                    If Cols.Length > 40 Then
                        PlayerDT.Rows.Add(Cols(0).ToString(), Cols(1).ToString(), Cols(37).ToString(), Cols(10).ToString(), Cols(47).ToString(), Cols(39).ToString(), Cols(34).ToString(), Cols(3).ToString)
                    End If
                Next


            End If
            DataGridView1.DataSource = PlayerDT
            DataGridView1.Update()

            memStream.Close()
        End If
    End Sub

    Sub Authenticate(ByVal rdata As String)
        Dim DigestKeyStart As Integer = rdata.LastIndexOf(":") + 2
        Dim DigestKeyLen As Integer = 16

        Dim PWResponse As String = rdata.Substring(DigestKeyStart, DigestKeyLen) & PassTXT.Text
        PWResponse = "login " & GenerateHash(PWResponse)
        SendCmd(PWResponse)
    End Sub

    Private Function GenerateHash(ByVal SourceText As String) As String
        Dim objMD5 As New System.Security.Cryptography.MD5CryptoServiceProvider
        Dim arrData() As Byte
        Dim arrHash() As Byte

        ' first convert the string to bytes (using UTF8 encoding for unicode characters)
        arrData = System.Text.Encoding.UTF8.GetBytes(SourceText)

        ' hash contents of this byte array
        arrHash = objMD5.ComputeHash(arrData)

        ' thanks objects
        objMD5 = Nothing

        ' return formatted hash
        Return ByteArrayToString(arrHash)
    End Function

    Private Function ByteArrayToString(ByVal arrInput() As Byte) As String

        Dim strOutput As New System.Text.StringBuilder(arrInput.Length)

        For i As Integer = 0 To arrInput.Length - 1
            strOutput.Append(arrInput(i).ToString("X2"))
        Next

        Return strOutput.ToString().ToLower

    End Function

    Private Sub Form1_FormClosing(sender As System.Object, e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing
        stm.Close()
        client.Close()
    End Sub

    Private Sub ConnectBTN_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ConnectBTN.Click
        client = New TcpClient(ServerIPTXT.Text, PortTXT.Text)
        stm = client.GetStream()
        SendCmd(CommandTXT.Text)
    End Sub

    Private Sub SendCommandBTN_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SendCommandBTN.Click
        SendCmd(CommandTXT.Text)
    End Sub

    Private Sub GetPlayerListBTN_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles GetPlayerListBTN.Click
        GetPlayerList()
    End Sub
End Class

顺便说一句,这是我在 stackoverflow 上的第一篇文章,但这些年来我从这个网站学到了很多 =)

4

0 回答 0