Visual Basic 2012網路程式設計-線上遊戲實作勘誤
勘誤之一: 對於讀者實在非常抱歉!因為本人一時的疏忽,本書第六與第七章TCP Server端的程式有個蠻嚴重的錯誤。雖然提供的程式可以執行,但容易造成多使用者上線時通訊物件的重疊使用,導致在通訊數次之後就會產生不穩定的現象。兩個單元內的伺服端程式之Listen副程序應作如下的修改。兩個程式專案修正後之版本可自此下載:TCP_Server,Chat_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() '結束此客戶的監聽執行緒
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() '結束此客戶的監聽執行緒
|
勘誤之二: 此為線上打桌球單元中拖曳球拍時送出己方球拍位置的程式,由於發現很多時候即使球拍物件之座標並未實際改變,也會連續觸發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
|