Visual Basic 2012網路程式設計-線上遊戲實作勘誤

 

勘誤之一:

對於讀者實在非常抱歉!因為本人一時的疏忽,本書第六與第七章TCP Server端的程式有個蠻嚴重的錯誤。雖然提供的程式可以執行,但容易造成多使用者上線時通訊物件的重疊使用,導致在通訊數次之後就會產生不穩定的現象。兩個單元內的伺服端程式之Listen副程序應作如下的修改。兩個程式專案修正後之版本可自此下載:TCP_ServerChat_Server

事實上本人原本的教學網頁內的程式就是正確的:

http://125.227.242.245/onlinegame/TCPbasic.htm

http://125.227.242.245/onlinegame/TCPChat.htm

程式修改的主要意義是將公用的Client與Th_Clt變數在Listen中複製到區域變數sck與Th,否則後續連線的使用者會搶用Client與Th_Clt,造成通訊的混亂。本人也尚未完全理解之處是,這種錯誤預期會造成第一次通訊就產生錯亂,但通常會持續三到四次通訊之後才開始異常。無論如何,這是本人過度簡化程式過程中的錯誤,特此致歉!

 

位置:P.6-10頁

原內容

    '監聽客戶訊息的程式

    Private Sub Listen()

        Do While True '持續監聽客戶傳來的訊息

            Try ' Sck 來接收此客戶訊息,inLen 是接收訊息的 Byte 數目

                Dim B(1023) As Byte    '建立接收資料用的陣列,長度須大於可能的訊息

                Dim inLen As Integer = Client.Receive(B) '接收網路資訊(Byte陣列)

                Dim Msg As String = Encoding.Default.GetString(B, 0, inLen) '翻譯實際訊息(長度inLen)

                Dim Cmd As String = Msg.Substring(0, 1) '取出命令碼 (第一個字)

                Dim Str As String = Msg.Substring(1)    '取出命令碼之後的訊息

                Select Case Cmd

                    Case "0" '有新使用者上線:新增使用者到名單中

                        HT.Add(Str, Client) '連線加入雜湊表,Key:使用者,Value:連線物件(Socket)

                        Listbox1.Items.Add(Str) '加入上線者名單

                    Case "9" '使用者離線:移除客戶的名單與連線資訊,並結束執行緒與關閉連線

                        HT.Remove(Str) '移除使用者名稱為Name的連線物件

                        Listbox1.Items.Remove(Str) '自上線者名單移除Name

                        Th_Clt.Abort() '結束此客戶的監聽執行緒

                        Client.Close() '關閉此客戶的連線

                End Select

            Catch ex As Exception

                '有錯誤時忽略,通常是客戶端無預警強制關閉程式,測試階段常發生

            End Try

        Loop

    End Sub
 

更正內容:

    '監聽客戶訊息的程式

    Private Sub Listen()

        Dim sck As Socket = Client '複製Client通訊物件到個別客戶專用物件Sck

        Dim Th As Thread = Th_Clt '複製執行緒Th_Clt到區域變數Th

        Do While True '持續監聽客戶傳來的訊息

            Try ' Sck 來接收此客戶訊息,inLen 是接收訊息的 Byte 數目

                Dim B(1023) As Byte    '建立接收資料用的陣列,長度須大於可能的訊息

                Dim inLen As Integer = sck.Receive(B) '接收網路資訊(Byte陣列)

                Dim Msg As String = Encoding.Default.GetString(B, 0, inLen) '翻譯實際訊息(長度inLen)

                Dim Cmd As String = Msg.Substring(0, 1) '取出命令碼 (第一個字)

                Dim Str As String = Msg.Substring(1)    '取出命令碼之後的訊息

                Select Case Cmd

                    Case "0" '有新使用者上線:新增使用者到名單中

                        HT.Add(Str, sck) '連線加入雜湊表,Key:使用者,Value:連線物件(Socket)

                        Listbox1.Items.Add(Str) '加入上線者名單

                    Case "9" '使用者離線:移除客戶的名單與連線資訊,並結束執行緒與關閉連線

                        HT.Remove(Str) '移除使用者名稱為Name的連線物件

                        Listbox1.Items.Remove(Str) '自上線者名單移除Name

                        Th.Abort() '結束此客戶的監聽執行緒

                        Client.Close() '關閉此客戶的連線

                End Select

            Catch ex As Exception

                '有錯誤時忽略,通常是客戶端無預警強制關閉程式,測試階段常發生

            End Try

        Loop

    End Sub


 

 

P.7-6

原內容

    '監聽客戶訊息的程式

    Private Sub Listen()

        Do While True '持續監聽客戶傳來的訊息

            Try ' Sck 來接收此客戶訊息,inLen 是接收訊息的 Byte 數目

                Dim B(1023) As Byte    '建立接收資料用的陣列,長度須大於可能的訊息

                Dim inLen As Integer = Client.Receive(B) '接收網路資訊(Byte陣列)

                Dim Msg As String = Encoding.Default.GetString(B, 0, inLen) '翻譯實際訊息(長度inLen)

                Dim Cmd As String = Msg.Substring(0, 1) '取出命令碼 (第一個字)

                Dim Str As String = Msg.Substring(1)    '取出命令碼之後的訊息

                Select Case Cmd

                    Case "0" '有新使用者上線:新增使用者到名單中

                        HT.Add(Str, Client) '連線加入雜湊表,Key:使用者,Value:連線物件(Socket)

                        Listbox1.Items.Add(Str) '加入上線者名單

                        SendAll(OnlineList) '將目前上線人名單回傳剛剛登入的人(包含他自己)

                    Case "9" '使用者離線:移除客戶的名單與連線資訊,並結束執行緒與關閉連線

                        HT.Remove(Str) '移除使用者名稱為Name的連線物件

                        Listbox1.Items.Remove(Str) '自上線者名單移除Name

                        SendAll(OnlineList) '將目前上線人名單回傳剛剛登入的人(不包含他自己)

                        Th_Clt.Abort() '結束此客戶的監聽執行緒

                        Client.Close() '關閉此客戶的連線

 

更正內容:

    '監聽客戶訊息的程式

    Private Sub Listen()

        Dim sck As Socket = Client '複製Client通訊物件到個別客戶專用物件Sck

        Dim Th As Thread = Th_Clt '複製執行緒Th_Clt到區域變數Th

        Do While True '持續監聽客戶傳來的訊息

            Try ' Sck 來接收此客戶訊息,inLen 是接收訊息的 Byte 數目

                Dim B(1023) As Byte    '建立接收資料用的陣列,長度須大於可能的訊息

                Dim inLen As Integer = sck.Receive(B) '接收網路資訊(Byte陣列)

                Dim Msg As String = Encoding.Default.GetString(B, 0, inLen) '翻譯訊息(長度inLen)

                Dim Cmd As String = Msg.Substring(0, 1) '取出命令碼 (第一個字)

                Dim Str As String = Msg.Substring(1)    '取出命令碼之後的訊息

                Select Case Cmd

                    Case "0" '有新使用者上線:新增使用者到名單中

                        HT.Add(Str, sck) '連線加入雜湊表,Key:使用者,Value:連線物件(Socket)

                        Listbox1.Items.Add(Str) '加入上線者名單

                        SendAll(OnlineList) '將目前上線人名單回傳剛剛登入的人(包含他自己)

                    Case "9" '使用者離線:移除客戶的名單與連線資訊,並結束執行緒與關閉連線

                        HT.Remove(Str) '移除使用者名稱為Name的連線物件

                        Listbox1.Items.Remove(Str) '自上線者名單移除Name

                        SendAll(OnlineList) '將目前上線人名單回傳剛剛登入的人(不包含他自己)

                        Th.Abort() '結束此客戶的監聽執行緒

                        Client.Close() '關閉此客戶的連線

勘誤之二:

此為線上打桌球單元中拖曳球拍時送出己方球拍位置的程式,由於發現很多時候即使球拍物件之座標並未實際改變,也會連續觸發MouseMove事件,導致發出之訊息重疊產生錯亂。因此加入座標必須實質改變才送訊息的條件式,可使通訊更為穩定。

P.9-13 9-8節程式碼

原內容

    Private Sub H1_MouseMove(sender As Object, e As MouseEventArgs) Handles H1.MouseMove

        If e.Button = Windows.Forms.MouseButtons.Left Then

            Dim X As Integer = H1.Left + e.X - mdx '試算拖曳終點位置

            If X < 0 Then X = 0 '不能超出左邊界

            If X > G.Width - H1.Width Then X = G.Width - H1.Width '不能超出右邊界

            H1.Left = X '設定X為球拍座標

            If ListBox1.SelectedIndex >= 0 Then '有選取遊戲對手,上線遊戲中

                Send("7" + H1.Left.ToString + "|" + ListBox1.SelectedItem) '傳送球拍位置訊息

            End If

        End If

    End Sub

 

更正內容:(新增粗體字部分)

    Dim oX As Integer

    Private Sub H1_MouseMove(sender As Object, e As MouseEventArgs) Handles H1.MouseMove

        If e.Button = Windows.Forms.MouseButtons.Left Then

            Dim X As Integer = H1.Left + e.X - mdx '試算拖曳終點位置

            If X < 0 Then X = 0 '不能超出左邊界

            If X > G.Width - H1.Width Then X = G.Width - H1.Width '不能超出右邊界

            H1.Left = X '設定X為球拍座標

            If ListBox1.SelectedIndex >= 0 Then '有選取遊戲對手,上線遊戲中

                If H1.Left <> oX Then '確定球拍有移動

                    Send("7" + H1.Left.ToString + "|" + ListBox1.SelectedItem) '傳送球拍位置訊息

                    oX = H1.Left '紀錄最新球拍位置

                End If

            End If

        End If

    End Sub