none
VB2008 TCP/IP 連線程序疑問 RRS feed

  • 問題

  • 請教各位大大小弟 這次在TCP連線中如何偵測斷線後 重新連結,以下是小弟的程式碼

     

    Imports System.Net
    Imports System.Net.Sockets
    Module Net
     Public TCP_Handstr As String = "46494E53"
     Public TCP_Length As String = "0000000C"
     Public TCP_Command As String = "00000000"
     Public TCP_ErrorCode As String = "00000000"
     Public TCP_NodeAddress As String = "00000000"
     Public Handstr As String = "80000200000000000000" 
      Public Link_Port As String
     DimTCP_myObj As New TCP_LINK
      Public Class TCP_LINK
      Public ipepRemote As IPEndPoint
      Public mySocket As New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
      Public PCIpAddress As IPAddress = IPAddress.Parse("192.168.0.5")
      Public myIpEndPoint As New IPEndPoint(PCIpAddress, 0)
      Public PLCIpAddress As IPAddress = (IPAddress.Parse("192.168.0.2")) 'PLC模組所設定IP
      Public PLCIpEndPoint As New IPEndPoint(PLCIpAddress, 9600)
      Public tcpClient As New TcpClient
     End Class
     
     Public Sub Link(ByVal SXD As String)
      Try
       'TCP_myObj.mySocket.Bind(TCP_myObj.myIpEndPoint)
       TCP_myObj.mySocket.Connect(TCP_myObj.PLCIpEndPoint)
       Dim sendBytes As [Byte]()
       ReDim sendBytes(SXD.Length \ 2 - 1)
       For ix As Integer = 0 To sendBytes.Length - 1
        sendBytes(ix) = CByte(Val("&H" & SXD.Substring(ix * 2, 2)))
       Next
       TCP_myObj.mySocket.Send(sendBytes, sendBytes.Length, SocketFlags.None)
       Dim bytes(30) As Byte
       TCP_myObj.mySocket.Receive(bytes, 30, SocketFlags.None)
       If bytes(11) = 1 Then
        Link_Port = Right("0" & Hex(CLng(bytes(19))), 2)
       End If
       PLCALM = False
      Catch ex As Exception
       If PLCALM = False Then
        MsgBox(ex.Message, MsgBoxStyle.Information, "網路連線錯誤")
       End If
       PLCALM = True
      End Try
    
     End Sub
    
     Public Sub TCP_READPLC(ByVal SXD As String, ByVal item As Integer, ByVal C As Integer)
      
      If TCP_myObj.mySocket.Connected = False Then
       TCP_Handstr = "46494E53"
       TCP_Length = "0000000C"
       TCP_Command = "00000000"
       TCP_ErrorCode = "00000000"
       TCP_NodeAddress = "00000000"
       Dim L As String = TCP_Handstr & TCP_Length & TCP_Command & TCP_ErrorCode & TCP_NodeAddress
       Link(L)
      Else
    
       Try
        TCP_myObj.mySocket.ReceiveTimeout = 1000
        TCP_myObj.mySocket.SendTimeout = 1000
        Dim SendItem As String
        Dim sendBytes As [Byte]()
        ReDim sendBytes(SXD.Length \ 2 - 1)
        For ix As Integer = 0 To sendBytes.Length - 1
         sendBytes(ix) = CByte(Val("&H" & SXD.Substring(ix * 2, 2)))
        Next
        TCP_myObj.mySocket.Send(sendBytes, sendBytes.Length, SocketFlags.None)
        SendItem = sendBytes(26) & sendBytes(27)
        System.Threading.Thread.Sleep(30)
        Dim bytes(item) As Byte
        TCP_myObj.mySocket.ReceiveBufferSize = item
        TCP_myObj.mySocket.ReceiveFrom(bytes, 0, item, SocketFlags.None, TCP_myObj.PLCIpEndPoint)
        For Item_Check As Integer = 0 To 3
         If bytes(Item_Check) <> sendBytes(Item_Check) Then
    
          Exit Sub
         End If
        Next
        Dim Sumheck As String = bytes(26) & bytes(27)
        If SendItem = Sumheck Then
         If bytes(28) = 0 And bytes(29) = 0 Then
    
    '數值解碼
           Else
          Exit Try
         End If
        End If
    
       Catch ex As Exception
        MsgBox(ex.Message, MsgBoxStyle.Information, "網路連線錯誤" & C)
    
       End Try
      End If
     End Sub
    End Module
    

    程式一開始時 會先執行 LINK 這段程式 這會與PLC建立聯結並抓取PLC配給PC的通訊埠(PLC會動態給,所以每次連線時會取得不同的埠)!因此連線後就不斷線

     

    利用TCP_READPLC這段程式 開始讀取PLC DM值, 若此時網路斷線或是連線逾時!斷線後 便無法重連,目前是遇到下列2種情形

    1.程式執行時若無連線 程式會停留在LINK 這段程式 "TCP_myObj.mySocket.Connect(TCP_myObj.PLCIpEndPoint)"當網路線插入後 "會出現連線已被軟體關閉"這個訊息之後便是"{"一旦通訊端中斷連接,您就只能再次非同步地重新連接,並且只可以連接至不同的 EndPoint。在作業完成之前,都必須在不會結束的執行緒上呼叫 BeginConnect。"}" 但我只能連接至相同的EndPoint(PLC端)

    2.若程式執行中拔出網路線!重新連結後 則會Show出上述第2個Alarm訊息

    請問大大們我這樣要如何寫重新連線的程序呢?

     


    新手上路
    2011年8月5日 上午 07:34

解答

  • 基本上connect沒有TimeOut的設定,  我曾經測過的結果大概是20秒沒錯

    然後就會出現Socket Execption.

    關於Socket Connect Timeout的既有討論

    http://social.msdn.microsoft.com/Search/zh-TW/?Refinement=112&query=Socket%20Connect


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。
    2011年8月8日 上午 06:01
    版主

所有回覆

  • 試試這個方式

    UI執行緒先產生一個子執行緒來執行 網路通訊, 當這個網路通訊拋出例外則通知UI執行緒發出 Thread.Abort強制把這個通訊執行緒給中斷掉.

    然後就再起一個執行緒執行通訊


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    2011年8月5日 上午 08:38
    版主
  • 大大您的意思小弟不太明白:我的理解如下

    我將PLC輪詢寫在READ_PLC_TCP放在ChooseThreads中去呼叫他

    在LOAD事件中 先呼叫一次 LINK 跟 呼叫ChooseThreads(1) 開啟一個FactorialThread

    用PLCALM=true時表示斷線

    用一個Timer元件來判斷網路是否斷線

    if PLCALM=true then

    重新呼叫LINK 跟 ChooseThreads(1)

    end

    這樣仍舊會在產生相同的異常訊息


    新手上路
    2011年8月5日 上午 09:51
  • 你有把Thread強制Abort掉嗎 ?

     


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。
    2011年8月5日 上午 10:00
    版主
  • 我在呼叫 將Thread Abort後才重新呼叫LINK 跟 ChooseThreads(1)不過結果不如預期!


    新手上路
    2011年8月5日 上午 11:32
  • 試著不要用Module, 把它整個改寫為一個Class, 用Module很容易產生共同變數的問題.

    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。

    2011年8月5日 上午 11:49
    版主
  • 我Try的結果,目前能抓到通訊中斷的方法是這樣!因為之前一開始就呼叫LINK 讓PC與PL取得連結並得到對應的通訊埠,所以當通訊中斷時 要在重連時會發生異常

    所以 改寫成這樣的程序

     Public Sub TCP_READPLC(ByVal SXD_Handstr As String, ByVal SXD_Lenrth As String, ByVal SXD_Command As String, ByVal item As Integer, ByVal C As Integer)
    
        Dim TCP_myObj As New TCP_LINK
        '取的TCP連線並回傳連接埠值
    
        Dim LINK_Handstr As String = "46494E53"
        Dim LINK_Length As String = "0000000C"
        Dim LINK_Command As String = "00000000"
        Dim LINK_ErrorCode As String = "00000000"
        Dim LINK_NodeAddress As String = "00000000"
        Dim LINKHandstr As String = "80000200000000000000"
        Dim LINKstring As String = LINK_Handstr & LINK_Length & LINK_Command & LINK_ErrorCode & LINK_NodeAddress
        TCP_myObj.mySocket.SendTimeout = 1000
        TCP_myObj.mySocket.ReceiveTimeout = 1000
        Try
    
          'TCP_myObj.mySocket.Bind(TCP_myObj.myIpEndPoint)
          TCP_myObj.mySocket.Connect(TCP_myObj.PLCIpEndPoint)
          Dim sendBytes As [Byte]()
          ReDim sendBytes(LINKstring.Length \ 2 - 1)
          For ix As Integer = 0 To sendBytes.Length - 1
            sendBytes(ix) = CByte(Val("&H" & LINKstring.Substring(ix * 2, 2)))
          Next
          TCP_myObj.mySocket.Send(sendBytes, sendBytes.Length, SocketFlags.None)
          Dim bytes(30) As Byte
          TCP_myObj.mySocket.Receive(bytes, 30, SocketFlags.None)
          If bytes(11) = 1 Then
            Link_Port = Right("0" & Hex(CLng(bytes(19))), 2)
          End If
          PLCALM = False
          'Link = True
        Catch ex As Exception
          'Link = False
          If PLCALM = False Then
            MsgBox(ex.Message, MsgBoxStyle.Information, "網路連線錯誤")
          End If
          PLCALM = True
        End Try
        If TCP_myObj.mySocket.Connected = False Then
        Else
          Try
            TCP_Length = "00000000"
            TCP_Length = bytes_lengh(SXD_Lenrth & "8000" & "0200" & "000000" & Link_Port & "0000" & SXD_Command)
            Dim SXD_Str As String = SXD_Handstr & TCP_Length & SXD_Lenrth & "8000" & "0200" & "000000" & Link_Port & "0000" & SXD_Command
    
            TCP_myObj.mySocket.ReceiveTimeout = 1000
            TCP_myObj.mySocket.SendTimeout = 1000
            Dim SendItem As String
            Dim sendBytes As [Byte]()
            ReDim sendBytes(SXD_Str.Length \ 2 - 1)
            For ix As Integer = 0 To sendBytes.Length - 1
              sendBytes(ix) = CByte(Val("&H" & SXD_Str.Substring(ix * 2, 2)))
            Next
            TCP_myObj.mySocket.Send(sendBytes, sendBytes.Length, SocketFlags.None)
            SendItem = sendBytes(26) & sendBytes(27)
            System.Threading.Thread.Sleep(30)
            Dim Item2 As Integer = TCP_myObj.mySocket.Available
            Dim bytes(item) As Byte
            TCP_myObj.mySocket.ReceiveFrom(bytes, 0, item, SocketFlags.None, TCP_myObj.PLCIpEndPoint)
            For Item_Check As Integer = 0 To 3
              If bytes(Item_Check) <> sendBytes(Item_Check) Then
                Exit Sub
              End If
            Next
            Dim Sumheck As String = bytes(26) & bytes(27)
            If SendItem = Sumheck Then
              If bytes(28) = 0 And bytes(29) = 0 Then
                Dim cun As Integer = (item - 30) / 2
                For item1 As Integer = 0 To cun - 1
                  Dim rereader As String = ""
                  For j As Integer = 0 To 1
                    Dim PQ As Integer = bytes((30 + (item1 * 2)) + j)
                    Dim s As String = Hex(PQ)
                    If Len(s) < 2 Then
                      s = "0" + s
                    End If
                    rereader += s
                  Next
                  Select Case C
                    Case 1 'DM 0~998
                      'READ1(item1) = rereader
                      myDataBuffer.DM(item1) = rereader
                    Case 2 'DM 999~1997
                      myDataBuffer.DM(999 + item1) = rereader
                    Case 3 'DM 1998~2996
                      myDataBuffer.DM(1998 + item1) = rereader
                    Case 4 '2997~3995
                      myDataBuffer.DM(2997 + item1) = rereader
                    Case 5 '3996~4994
                      myDataBuffer.DM(3996 + item1) = rereader
                    Case 6
                      For i As Integer = 0 To 15
                        myDataBuffer.W_State((item1 * 16) + i) = CInt(Mid(Hex2Bin(rereader), 16 - i, 1))
                      Next
                    Case 7
                      For i As Integer = 0 To 15
                        myDataBuffer.H_State((item1 * 16) + i) = CInt(Mid(Hex2Bin(rereader), 16 - i, 1))
                      Next
                  End Select
                Next
              Else
                Exit Try
              End If
            End If
            TCP_myObj.mySocket.Close()
          Catch ex As Exception
            PLCALM = True
            MsgBox(ex.Message, MsgBoxStyle.Information, "網路連線錯誤" & C)
            TCP_myObj.mySocket.Close()
          End Try
        End If
      End Sub
    

    這樣通訊中斷後再重連就目前測試是OK的!旦通訊逾時的部分!

      TCP_myObj.mySocket.ReceiveTimeout = 1000
      TCP_myObj.mySocket.SendTimeout = 1000

    實際逾時跳出會在網路拔除的20秒後發生!已執行中斷來看

     TCP_myObj.mySocket.Connect(TCP_myObj.PLCIpEndPoint) 請問這邊的反應時間要如何設定?


    新手上路
    2011年8月8日 上午 02:45
  • 基本上connect沒有TimeOut的設定,  我曾經測過的結果大概是20秒沒錯

    然後就會出現Socket Execption.

    關於Socket Connect Timeout的既有討論

    http://social.msdn.microsoft.com/Search/zh-TW/?Refinement=112&query=Socket%20Connect


    在現實生活中,你和誰在一起的確很重要,甚至能改變你的成長軌跡,決定你的人生成敗。 和什麼樣的人在一起,就會有什麼樣的人生。 和勤奮的人在一起,你不會懶惰; 和積極的人在一起,你不會消沈; 與智者同行,你會不同凡響; 與高人為伍,你能登上巔峰。
    2011年8月8日 上午 06:01
    版主
  • 不過在連線時先建立一個連線

       TCP_myObj.mySocket.Bind(TCP_myObj.myIpEndPoint)

    這樣通訊一斷便可立即反映,至少現階段測是OK的!


    新手上路
    2011年8月8日 上午 06:45