這一篇來談到如何使用使用TcpClient與TcpListener類別來實作TCP的通訊程式,顧名思義TcpClient當然是作為Clinet端使用;而TcpListener則是作為Server端使用。
這一篇來談到如何使用使用TcpClient與TcpListener類別來實作TCP的通訊程式,顧名思義TcpClient當然是作為Clinet端使用;而TcpListener則是作為Server端使用。
照例先來分類一下TcpClient的建構函式:
| 1 | 自動給本機Port號 | TcpClient() TcpClient(AddressFamily)  | 
		
| 2 | 依IPEndPoint決定本機Port號 | TcpClient(IPEndPoint) | 
| 3 | 指定遠端主機Hostname與Port號 | TcpClient(String, Int32) | 
至於TcpListener的建構函式則有三種:
| 1 | 指定本機Port號﹝這個方法在 .NET 2.0 版本被註明已過時﹞ | TcpListener(Int32) | 
| 2 | 依IPEndPoint決定本機Port號 | TcpListener(IPEndPoint) | 
| 3 | 依傳入的IPAddress與Port決定 | TcpListener(IPAddress, Int32) | 
下方所顯示的是使用使用TcpClient與TcpListener類別的簡要流程,以下的範例程式碼也是以這個流程為基礎所撰寫的。
        ![]()
右邊是TcpListener的畫面,在此就不多贅述。
TcpListener程式重點解說:
1.在Button1.Click事件中,並取得主畫面中NumericUpDown1.Value作為本機TCP Port號的依據;使用Thread (ParameterizedThreadStart) 指定委派的方法為 StartListen,並將iPort的值傳遞過去。
Dim ListenThread As New Thread(AddressOf StartListen)
ListenThread.IsBackground = True
ListenThread.Start(iPort)
2.在自訂的StartListen方法中建立TcpListener的執行個體,然後以TcpListener.Start方法啟動TcpListener,使其進入接聽封包狀態。並在Do....Loop迴圈內叫用TcpListener.AcceptSocket方法﹝也可以用TcpListener.AcceptTcpClient方法,不過就MSDN文件庫的建議為TcpListener.AcceptSocket較TcpListener.AcceptTcpClient具有彈性﹞。
myTcpListener = New TcpListener(IPAddress.Any, iPort)
            Dim ClientSocket As Socket
            myTcpListener.Start()
            Do
                ClientSocket = myTcpListener.AcceptSocket()
                If ClientSocket.Connected = True Then
                    Dim myObj As New CSState
                    myObj.myTcpListener = myTcpListener
                    myObj.ClientSocket = ClientSocket
                    myObj.mystring = Now.ToString("yyyy/MM/dd HH:mm:ss") & "已連線"
                    DisplayMsg1(myObj)
                    Dim ReceiveThread As New Thread(AddressOf ReceiveData)
                    ReceiveThread.IsBackground = True
                    ReceiveThread.Start(myObj)
                    iCount += 1
                End If
            Loop
3.此執行緒將會在TcpListener.AcceptSocket方法中暫止等待,直到遠端的Socket完成連接才會繼續往下執行。
4.在成功接受連接後,將必要資訊包裝為自訂類別CSState的執行個體,使用Thread (ParameterizedThreadStart) 指定委派的方法為ReceiveData,並將自訂類別CSState的執行個體傳遞過去。
               Dim ReceiveThread As New Thread(AddressOf ReceiveData)
              ReceiveThread.IsBackground = True
              ReceiveThread.Start(myObj) 
5.在ReceiveData方法中使用NetworkStream (Socket)建構函式建立NetworkStream執行個體,爾後使用NetworkStream.Read方法讀回串流中的資料。
     Private Sub ReceiveData(ByVal state As Object)
        Dim myObj As New CSState
        myObj.ClientSocket = CType(state, CSState).ClientSocket
        myObj.myTcpListener = CType(state, CSState).myTcpListener
        myObj.mystring = ""
        Dim myNetworkStream As New NetworkStream(myObj.ClientSocket)
        Dim InBytesCount As Integer = 0
        Dim myReceiveBytes(1023) As Byte
        Dim i As Integer = 0
        While True
            Try
                InBytesCount = myNetworkStream.Read(myReceiveBytes, 0, myReceiveBytes.Length)
                System.Threading.Thread.Sleep(100)
                If InBytesCount = 0 Then
                    Exit While
                End If
                myObj.mystring = Encoding.GetEncoding(950).GetString(myReceiveBytes).TrimEnd().TrimStart()
                DisplayMsg1(myObj)
            Catch ex As Exception
                MessageBox.Show(ex.ToString)
                Exit Sub
            End Try
        End While
    End Sub
至於TcpClient的部份, 那就更為簡單了。
1.產生TcpClient執行個體。
myTcpClient = New TcpClient(myIPEndPoint)
2.產生遠端伺服器IPEndPoint執行個體。
3.使用TcpClient.Connect (IPEndPoint)方法連接到伺服器。
Dim RemoteIpEndPoint As New IPEndPoint(ServerIpAddress, iPort)
myTcpClient.Connect(RemoteIpEndPoint)
4.使用TcpClient.GetStream方法建立NetworkStream執行個體。
myNetworkStream = myTcpClient.GetStream()
5.使用NetworkStream.Write方法將資料寫入網路串流中。
myNetworkStream.Write(myBytes, 0, myBytes.Length)
       撰寫簡單的TCP Socket的程式其實只要掌握重點的執行個體建構函式與少數幾個方法就可達成,並不是太困難,至於Server與Client要達成互相通訊﹝目前這範例只有Client送資料給Server﹞的功能,就請各位藉由這個基礎去變化,相信應該是手到擒來才是。
2018/04/08 註:我把範例程式重新上傳到 github,下載位址 https://github.com/billchungiii/SyncTcpSamples