none
Socket 連線至 TCPIP的問題 ///請高手指導 RRS feed

  • 問題

  • 各位高手大大, 大家好 :
    小弟剛接觸VB不到2個月 , 因為對.NET很有興趣 , 故投入了VB開始了程式的學習及編寫
    經過2個星期的不停鑽研 ,  在一般Windows的程式視窗架構已經沒有問題了(一般的視窗操作) ,
    但在TCPIP這一部分還是遇到了瓶頸無法突破(書買了好多....) , 但還是一直無法解決
    請各位先進及大大   多多指教指教 :
    內容新說明整理 :
    1 . 設計內容方向 :
        a . 設計一個Client端進行TCP的連線 , 伺服端的IP為192.168.0.127 , Port : 23
            故視窗只需要3個Botton (連線 / 中斷 / Send ) , 3個TextBox (IPaddress , Port , 訊息傳送文字)
            再加上一個ListBox (Show秀出指令的往來)
        b . 伺服端為一個自動控制器(客製化成熟的成品) , 可接受FTP(不需登入)  及 TCPIP連線
        c . TCPIP連上後 , Client端可傳送指令給伺服端 , 伺服端只接受ASCII碼的文字 , 伺服端收到
             正確的指令時會回應相對的訊息 (ASCII)
          (例如  : 我送出  " $abcdefg "    , 若那是正確的指令格式 , 伺服端會回傳類似的訊息)
    2 . 目前先我有以Windows系統直接進行FTP==>可以正常連線及上傳或下傳檔案 ==>伺服器是正常運作的
                                                                                                          (果然是我的程式不行.....)
    3 . 目前的問題 Sad我使用VB 2008 , 連線到伺服端是OK的 , Ping的到主機)
       a . TCP連線成功後 ,若進行中斷後想再連線 ==> 無法再連 , 伺服端拒絕被登入 (必需重新開機後才能再連線)
           為何我已使用了SocketClient.Close() , 中斷後卻不能再連線???????
       
        b . 傳送指令的格式好像不對 , 伺服端只接受ASCII的編碼(回傳也是ASCII)
            (我是參考MSDN及以書上的說明來進行程式的編寫的)
    以下是我的主要程式段
    ' -----  命名空間-----
    Imports System.Net.Sockets
    Imports System.Net
    Imports System.Text
    '------------------------------------------
    Public Class main
        Dim SocketClient As Socket    ' 宣告Socket
        Dim data() As Byte                ' 宣告定義接收資料的位元組陣列
        Dim IsConnected As Boolean
        Dim Connect As AsyncCallback                 '指派連線
        Dim ReceiveData As AsyncCallback            '指派接收資料
        Dim SendData As AsyncCallback                '指派傳送的資料
    ''
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            IPAddTextBox.Text = "192.168.0.127"
            PortTextBox.Text = "23"
            IsConnected = False
            CheckState()
            '建立委派
            Connect = New AsyncCallback(AddressOf OnConnect)
            ReceiveData = New AsyncCallback(AddressOf OnReceive)
            SendData = New AsyncCallback(AddressOf OnSend)
        End Sub
    ''
    Private Sub btnCreate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCreate.Click
            Try
              SocketClient = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
             Dim dataLength As Integer
                dataLength = CInt(SocketClient.GetSocketOption( _
                                  SocketOptionLevel.Socket, _
                                  SocketOptionName.ReceiveBuffer))
               ReDim data(dataLength)
                '繫結IP位址與通訊埠
                Dim ep As New IPEndPoint(IPAddress.Parse(IPAddTextBox.Text), _
                                         CInt(PortTextBox.Text))
               SocketClient.BeginConnect(ep, Connect, SocketClient)
                SendListBox.Items.Add("連線中!")
                IsConnected = True
                CheckState()
            Catch sk As SocketException
                MessageBox.Show("SocketException ErrodCode:" & _
                           sk.ErrorCode.ToString & vbCrLf & _
                           "SocketException Message:" & sk.Message, _
                           "SocketException", _
                           MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub
    '''
    Private Sub btnClose_Click(ByVal sender As System.Object,  ByVal e As System.EventArgs) Handles btnClose.Click
           SocketClient.Close()
            IsConnected = False
            CheckState()
            If IsConnected = True Then
                Disconnect()
            End If
        End Sub
    '''''
    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
           Dim byteSend() As Byte = Encoding.ASCII.GetBytes(SendTextBox.Text)
           SocketClient.BeginSend(byteSend, 0, byteSend.Length, SocketFlags.None, SendData, SocketClient)
           SendListBox.Items.Add(SendTextBox.Text)
        End Sub
    ''''
    Private Sub CheckState()
            PortTextBox.Enabled = Not IsConnected
            btnCreate.Enabled = Not IsConnected
            btnClose.Enabled = IsConnected
            btnSend.Enabled = IsConnected
            SendTextBox.Enabled = IsConnected
            Me.Update()
        End Sub
    ''''''
    Public Sub OnConnect(ByVal ar As IAsyncResult)
            Try
                '結束連接至Socket伺服端
                SocketClient.EndConnect(ar)
                '將接收資料的程序指派給UpdateReceiveMessage
                Me.Invoke(New delSendMessage( _
                          AddressOf Me.UpdateSendMessage), "已連入伺服器")
                '開始接收資料
                SocketClient.BeginReceive(data, 0, data.Length, _
                             SocketFlags.None, ReceiveData, SocketClient)
            Catch sk As SocketException
                MessageBox.Show("SocketException ErrodCode:" & _
                           sk.ErrorCode.ToString & vbCrLf & _
                           "SocketException Message:" & sk.Message, _
                           "SocketException", _
                           MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub
    '''''''''''''''
        Public Sub OnReceive(ByVal ar As IAsyncResult)
            If Not IsConnected Then
                Exit Sub
            End If
            Dim SocketServer As Socket = CType(ar.AsyncState, Socket)
            Try
                Dim recvLength As Integer
                recvLength = SocketServer.EndReceive(ar)
                If recvLength = 0 Then
                            SocketClient.Close()
                    IsConnected = False
                    Me.Invoke(New delUpdateUI(AddressOf Me.UpdateUI))
                Else
                    Dim RecvStr As String = Encoding.ASCII.GetString(data, 0, recvLength)
                    Me.Invoke(New delReceiveMessage( AddressOf Me.UpdateReceiveMessage), RecvStr)
                    SocketClient.BeginReceive(data, 0, data.Length, SocketFlags.None, ReceiveData, SocketClient)
                End If
            Catch sk As SocketException
                If sk.ErrorCode = 10054 Then
                   Me.Invoke(New delReceiveMessage(AddressOf Me.UpdateReceiveMessage), "伺服端中斷連接")
                   IsConnected = False
                    Me.Invoke(New delUpdateUI(AddressOf Me.UpdateUI))
                Else
                    MessageBox.Show("SocketException ErrodCode:" & _
                                    sk.ErrorCode.ToString & vbCrLf & _
                                    "SocketException Message:" & sk.Message, _
                                    "SocketException", _
                                    MessageBoxButtons.OK, MessageBoxIcon.Error)
                End If
            Catch dx As ObjectDisposedException
            Catch ex As Exception
             MessageBox.Show(ex.ToString, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub
    ''''''''''''''''
        Public Sub OnSend(ByVal ar As IAsyncResult)
            If Not IsConnected Then
                Exit Sub
            End If
            If SocketClient Is Nothing Then
                Exit Sub
            End If
         SocketClient.EndSend(ar)
        End Sub
    ''''''''''''''''''''''''''''
        '指派程序
        Public Delegate Sub delReceiveMessage(ByVal RecvStr As String)
        Public Delegate Sub delSendMessage(ByVal SendStr As String)
        Public Delegate Sub delUpdateUI()
    ''''''''''''''''''''''''''''''''''''''''''
        Public Sub UpdateReceiveMessage(ByVal RecvStr As String)
            SendListBox.Items.Add(RecvStr)
        End Sub
    ''''''''''''''''''''''''''''''''''''''''''''''''
        Public Sub UpdateSendMessage(ByVal SendStr As String)
            SendListBox.Items.Add(SendStr)
        End Sub
    ''''''''''''''''''''''''''''''''''''''''''''''''
        Public Sub UpdateUI()
            CheckState()
        End Sub
    '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
        Public Sub Disconnect()
            If Not IsConnected Then
                Exit Sub
            End If
            If SocketClient Is Nothing Then
                Exit Sub
            End If
            Try
                SocketClient.Close()
            Catch sk As SocketException
                MessageBox.Show("SocketException ErrodCode:" & _
                                sk.ErrorCode.ToString & vbCrLf & _
                                "SocketException Message:" & sk.Message, _
                                "SocketException", _
                                MessageBoxButtons.OK, MessageBoxIcon.Error)
            Catch ex As Exception
                MessageBox.Show(ex.ToString, "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
        End Sub
    End Class
    =======================================================================
    有請各位先進及大大指導一下
    感恩~~~~~~~~~
     
     
    2008年12月11日 上午 10:21

解答

  • TO : LongHairPan 以及 心冷熱情熄 兩位大大

    我的這個問題已經解決了,經過兩個禮拜的努力終於有了第一步的開始
    才剛學VB的我很幸運有大家的協助,才能有點小成果
    相信下一步更是有更大的挑戰在等著我,
    在此特謝兩位的幫忙,謝謝你們

    最後,解決問題的地方:
    我把 Dim byteSend() As Byte = Encoding.ASCII.GetBytes(SendTextBox.Text) 的地方
    改成 Dim byteSend() As Byte = Encoding.ASCII.GetBytes(SendTextBox.Text + vbCr )
    就解決了,昨天我在練習其它執行緒時突然想到,如果加個vbCrlf 或者vbCr會怎麼樣
    結果就成功了
    真是瞎猫碰到死老鼠,超級好運。規格書也沒說明文字結尾要加入 enter的信號
    就這樣

    往後若有問題會再請教各位高手旳,謝謝大家 
    2008年12月15日 下午 02:28

所有回覆

  • telnet 的部分可以先搜尋 TcpClient 23

    http://forums.microsoft.com/MSDN-CHT/Search/Search.aspx?words=TcpClient+23&localechoice=31748&SiteID=14&searchscope=forumscope&ForumID=232

     

    Code Snippet

       a . TCP連線成功後 ,若進行中斷後想再連線 ==> 無法再連 , 伺服端拒絕被登入 (必需重新開機後才能再連線)
           為何我已使用了SocketClient.Close() , 中斷後卻不能再連線???????

     

     

    這表示你 server 端的 socket.Listen 跟 socket.accept 兩個寫的有問題。只有把 Listen 的拿去做 accept (變成只允許一條連線) ,結束後沒有恢復 Listen ,才會如此。

     

    先前有很多討論了,先搜尋 socket accept

    http://forums.microsoft.com/MSDN-CHT/Search/Search.aspx?words=socket+accept&localechoice=31748&SiteID=14&searchscope=forumscope&ForumID=232

    2008年12月11日 下午 02:25
  •  心冷熱情熄 寫信:

    telnet 的部分可以先搜尋 TcpClient 23

    http://forums.microsoft.com/MSDN-CHT/Search/Search.aspx?words=TcpClient+23&localechoice=31748&SiteID=14&searchscope=forumscope&ForumID=232

     

    Code Snippet

       a . TCP連線成功後 ,若進行中斷後想再連線 ==> 無法再連 , 伺服端拒絕被登入 (必需重新開機後才能再連線)
           為何我已使用了SocketClient.Close() , 中斷後卻不能再連線???????

     

     

    這表示你 server 端的 socket.Listen 跟 socket.accept 兩個寫的有問題。只有把 Listen 的拿去做 accept (變成只允許一條連線) ,結束後沒有恢復 Listen ,才會如此。

     

    先前有很多討論了,先搜尋 socket accept

    http://forums.microsoft.com/MSDN-CHT/Search/Search.aspx?words=socket+accept&localechoice=31748&SiteID=14&searchscope=forumscope&ForumID=232

     

     

    謝謝您的回應 :

    您所提供的文章 , 我進行爬了許多文章 , 但還是沒有解決問題 , 應該是我的程式能力還太薄弱~~~~

    有關於在我寫的Client端程式, 在執行中斷連線後 , 想要再連上線, 是不被Server允許的

    但我現在對應Server端是一個工業用的成品控制器(內含Server端), 這是已經產品化的東西 ,程式是固定的

    我有試著用連線軟體 : Windows的超級終端機 : 去進行連線-->正常,傳送指令 -->Server會正常回應給我

    (有人會說那就直接用超級終端機就好了啊!! , 因為功能上還有許多需要加入的 , 所以不得不設計一個新的程式~~~)

    現在我的問題變成是 , 我確定我的程式已經可連上Server端 ,

    在我交錯比對下(以比對超級終端機的使用) , 問題點可能在 , 我送出去的文字格式吧

    雖然該控制器的規格書上說明 , 通訊的傳輸是用ASCII 編碼--> 可是超級終端機送出去的是String格式才對

    故 , 我在程式上修正 以文字格式來傳送 , 但也是失敗的 , 我也有嘗試以TCPClient的類別來寫,但也是失敗的

    問題 :

    1 . Socket類別 , 在送出的資料是以Byte()的格式 , 若要用純文字送出Message的話

         以我寫的程式, 怎麼修正呢?

    2 . 程式中斷的 程序寫法 , 是不是有不當之處呢 ?

    請高手們指點指點

     

    感激不盡

    2008年12月12日 上午 07:59
  • 1. 用 ascii 嗎? 試試 system.text.encoding.ascii.getbytes 看行不行
    2. 程式中斷是指斷線嗎? 在下 close 之前, 先下 shutdown, 我習慣在 close 之後把 socket 的實體設為 nothing,
        下次 connect 時再 new 一個, 好像 disconnect 是可以重覆使用一個 socket 吧, 但我沒用過,
        畢竟網路程式我目前寫的, 並沒有寫過需要斷線連線很頻繁的, 所以沒什麼 performance 的問題

    另外, 使用 socket , 一定要做好 mutex 保護, 不然很容易因為寫一堆 try catch , 最後不知道死在哪裡....
    2008年12月12日 下午 06:16
  • 有控制字元時,要直接用 byte() ,有中文時,要用 big5 來做 Enocing.GetBytes

    2008年12月13日 上午 01:19
  • TO : LonghairPan
    資料流的編碼方式,我試了好多次,包含Asciiencoding / encoding.ascii / emcoding.default等等

    2008年12月13日 上午 03:05
  • 首先我想𨤳清連線狀況 :
    我使用了以下簡單的測試,確認是否有連線成功

    Imports System.Net
    Imports System.Net.Sockets
    Imports System.Text

    Public Class Form1
        Dim MyTcpClient As Socket
        Dim data() As Byte

        Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        End Sub

        Private Sub btnCreate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCreate.Click
            MyTcpClient = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
            MyTcpClient.Connect(IPAddress.Parse("192.168.0.127"), 23)

            If MyTcpClient.Connected = True Then
                ListBox_Message.Items.Add("已經連線")
            Else
                ListBox_Message.Items.Add("沒有完成連線")
            End If
    End Class
    ===========================
    執行的結果,是顯示 已經連線
    這個結果是表示,網路通了,那我怎麼確保Server端已經可以接收命令了呢
    因為我再用簡單的指令向Server發送,但Server都沒反應
    我使用微軟的超級終端機使用相同的指令,Server的LED 燈會變化
    若以以上的敘述,以下是針對我寫的程式碼的問題發問( 我先把問題從最根本來𨤳清)
    1、連線真的成功了嗎 ?,怎麼確認呢?有沒有什麼方法可以確認
    2、送出的指令有兩種可能,第一種:沒傳出去(因為根本還沒連線),第二種:送出去的指令格式不對
      所以Server不理我

    請教一下心冷熱情熄,有沒有好的建議,請指教

    2008年12月13日 上午 03:32
  • 沒看到你的 Send 程式碼。

     

    前面給的搜尋連結,這篇看過嗎?

    http://forums.microsoft.com/msdn-cht/ShowPost.aspx?PostID=631498&SiteID=14

    2008年12月13日 上午 05:39
  • Send的程碼如下:

    Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
            If txtcmd.Text = Nothing Then
                ListBox_Message.Items.Add("指令欄為空白")
            Else
                
                Dim byteSend() As Byte = Encoding.Default.GetBytes(txtcmd.Text)
                MyTcpClient.Send(byteSend, 0, byteSend.Length, SocketFlags.None)

            End If
        End Sub

    請指教
    ps : 中午去書局爬了許多文,並沒有收護
    2008年12月13日 上午 07:39
  • 網路有沒有連線成功用 netstat 看就可以了,
    如果你打的字都一樣, 那你可以試試不要一整串傳過去, 一次傳一個 byte,
    因為在終端機上, 你輸入的東西都會直接 send 出去,
    比如說你打 12345 , 會分別送出 {0x31},{0x32},{0x33},{0x34},{0x35} 5 個byte,
    除非用貼上的, 那會一次送出,
    所以你可以試試一次送出 1 個 byte , 或是依字元數分開送,
    因為不清楚你的 server 端的 parser , 所以如果終端機可以成功傳送, 那就盡量讓傳送方式跟終端機一樣吧
    2008年12月13日 上午 08:55
  • LongHairPan您好
    我的需求是指令必而一次往上送 例如:#1ABCSDE  送出給Server, Server收到後會回應Client相對的字元

    這麼說好了:
    我現在電腦的網路( 硬體)的TCP/TP的設定為 192.160.0.5
    Server端的IP為192.168.0.127 Port: 23
    以網路線直接連接電腦及Server
    在WindowsXP的命令提示視窗中 輸入 
    C:\>netstat
    ==> Server回應 :
     Foreign Address  為 192.168.0.127:telnet
       State : ESTABLISHED
    表示在硬體方面基本上網路是通的
    而我需要設計的程式,簡單說是很類似 Windows 的超級終端機的模式,但要加入更多的功能

    以我最上面的程式碼中,我曾改了很多種方式去進行指令的下達(TcpClient / SocketClient ),但Server還是沒有回應

    而我的指令一次是必需全部送出的,
    例如:Client端下達:#1ABC
        Server回應:#1EDF    給Client端

    請教各位高手,若要寫成類似Telnet的交談模式,我最上面的程式碼需要做多大的修正呢

    2008年12月13日 上午 11:46
  • 看你的程式應該是沒什麼大問題,
    你要不要乾脆掛個 sniffer 去看看終端機跟你的 server 到底送了些什麼....
    2008年12月13日 上午 11:58
  • 先感謝大家的回應與幫忙
    LongHairPan大大所言 sniffer 我不懂怎麼做,能提供簡單的作法嗎

    2008年12月13日 下午 02:43
  •  

    謝謝大家的指導 , 我想我要再好好的鑽研一下有關TCPIP / FTP 

    這一個主題的問題, 我會繼續努力下去, 有解時會與大家分享

     

    謝謝

    2008年12月13日 下午 04:56
  • 自己寫個 sniffer 似乎有點麻煩,
    去找個 packetyzer 來攔吧....免費不錯用....
    2008年12月13日 下午 05:32
  • TO : LongHairPan 以及 心冷熱情熄 兩位大大

    我的這個問題已經解決了,經過兩個禮拜的努力終於有了第一步的開始
    才剛學VB的我很幸運有大家的協助,才能有點小成果
    相信下一步更是有更大的挑戰在等著我,
    在此特謝兩位的幫忙,謝謝你們

    最後,解決問題的地方:
    我把 Dim byteSend() As Byte = Encoding.ASCII.GetBytes(SendTextBox.Text) 的地方
    改成 Dim byteSend() As Byte = Encoding.ASCII.GetBytes(SendTextBox.Text + vbCr )
    就解決了,昨天我在練習其它執行緒時突然想到,如果加個vbCrlf 或者vbCr會怎麼樣
    結果就成功了
    真是瞎猫碰到死老鼠,超級好運。規格書也沒說明文字結尾要加入 enter的信號
    就這樣

    往後若有問題會再請教各位高手旳,謝謝大家 
    2008年12月15日 下午 02:28
  • 一般標準通訊協定都要加 Cr + Lf ...

    通常分下面兩種:

    a. 單行:

    Body Cr + Lf

     

    b. 多行:

    Header

    Line1 Cr + Lf

    ...

    LineN Cr + Lf

    Cr + Lf

    Body

    Line1 Cr + Lf

    ...

    LineN Cr + Lf

    Cr + Lf + . + Cr + Lf

    2008年12月15日 下午 02:49
  • 很顯然你在終端機打完指令後有按下[Enter]鍵
    也就是送出 cr (0x0D) 及 lf (0x0A)....
    2008年12月15日 下午 03:07
  • 心冷熱情熄 大大:
    我又學到了新觀念了,謝謝你,或許這些觀念本來就應該要知道的
    新手嘛,多多包含。

    我的下一個目標是完成FTP 的檔案下載及上傳 ﹣> 這個好像比較沒那麼難

    最後是Binary的轉檔程序 Binary轉成ASCII的文字檔,編輯完後再轉回Binary
    聽說,資料處理就沒那麼簡單了,

    先弄好FTP再說 吧

    2008年12月15日 下午 03:14