现在的位置: 首页 > 综合 > 正文

制作一个网络通讯类(一)

2018年01月22日 ⁄ 综合 ⁄ 共 4880字 ⁄ 字号 评论关闭

http://coffecoco.bokee.com/806222.html

制作一个网络通讯类(一)- -

                                      

 

简介

TcpListener类提供一些简单方法,用于在同步阻塞模式下侦听和接受传入连接请求。

TcpClient 类提供了一些简单的方法,用于在同步阻塞模式下通过网络来连接、发送和接收流数据。

为了使用方便,我利用.Net提供的这两个类作了一个网络通讯用的类CTcpTalk。

 

工作原理和使用方法

* 每个CTcpTalk对象中包含一个用于监听的TcpListener部件,一个用于传输数据的TcpClient部件,和一个用于接收连接请求的TcpClient部件。

* 在创建一个CTcpTalk时需要指定要使用的端口号。然后使用CTcpTalk.Open开启对网络的监听。

* 接收数据:当监听到有数据传送到本机时,使用接收连接请求的TcpClient部件接收对方的连接请求以及发送来的数据。接收完毕后关闭TcpClient部件,并触发DataArrival事件,可以使用GetData()函数获取收到的数据。

* 发送数据:设置接收方的名称和端口,使用传输数据的TcpClient部件请求连接,连接成功后发送数据。数据发送完毕之后关闭TcpClient部件,并触发SendComplete事件。

 

设计中的问题

* 由于TcpListener和TcpClient都是工作在同步阻塞模式下,因此数据传输和监听都使用了单独的线程。

* 对于TcpListener的监听线程,因为是阻塞的模式,所以在关闭监听时,需要先由本机向本机自己发一个连接请求,以解除监听线程的阻塞,然后通过相应量的设置,退出监听循环,关闭监听。在监听阻塞状态下直接关闭监听会导致错误,通过错误陷阱隐藏后,似乎也不会影响后面的使用。

* 使用流模式读取和发送数据,为了方便而采用了流的同步读写。

* 设计为发送方申请建立连接、发送接收完毕后立刻断开连接的模式。类似于点对点的模型,没有服务器客户端之分。参加通讯的机器只需要维持一个监听线程就可以了。而不必保留已连接列表并随时检查列表中各个项的连接状态。这也是因为采用了同步读写模式,如果阻塞流的读线程反而会大大降低性能。

* 对于传输数据量的大小,有8K字节的限制。由于使用了Unicode编码解码,所以实际的传输量测试为每次4K以下。可以通过外部编程对大数据量进行分页传输,但是在内部仍然是每次传输前建立连接、传输完毕后断开连接的方式。因此对于过大的数据需要消耗额外的资源用于频繁建立和断开连接。

* 因为可能要用于.Net Framework精简版,所以方法、事件和属性都考虑使用受精简版支持的版本。

 

测试程序界面(单机测试)

本界面为单机测试结果。此程序也可用于多机。

按钮加入网络

启动本机的网络监听。此按钮在已经启动监听后不可用

Name = BJoinNet

按钮退出网络

关闭本机的网络监听。关闭之后将无法再接收连接请求。此按钮在监听关闭时不可用

Name = BExitNet

按钮关闭程序

关闭程序

Name = BClose

按钮发送

发送文本框中的内容。在未加入网络时此按钮不可用。

Name = BSend

文本框发送的内容

Name = TBSend

MultiLine = True

ScrollBars = Vertical

文本框接收的内容

Name = TBRecv

MultiLine = True

ScrollBars = Vertical

ReadOnly = True

文本框状态监视

Name = TBState

MultiLine = True

ScrollBars = Vertical

ReadOnly = True

测试程序代码

组件声明

    Private WithEvents sck1 As CTcpTalk
界面加载
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        '获取本机名称和IP
        Try
            LLocalName.Text = Dns.GetHostName
            LLocalIP.Text = Dns.Resolve(LLocalName.Text).AddressList(0).ToString
        Catch ex As Exception
            LLocalName.Text = "无法获得主机名"
            LLocalIP.Text = "无法获得主机IP"
        End Try
        sck1 = New CTcpTalk
        '重绘界面
        SetUIDisconnect()
End Sub
界面关闭
    Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
        If sck1 Is Nothing Then
        Else
            If sck1.State <> CTcpTalk.StateConstants.sckClosed Then
                sck1.Close()
            End If
        End If
        Application.Exit()
    End Sub
按钮加入网络
    Private Sub BJoinNet_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BJoinNet.Click
        '检查端口号
        If TBPort.Text = "" Then
            MsgBox("请输入端口号")
            Exit Sub
        End If
        Dim port As Long
        Try
            port = CLng(TBPort.Text)
        Catch ex As Exception
            MsgBox("端口号格式错误, 请重新设置")
            Exit Sub
        End Try
        '开启监听
        sck1 = New CTcpTalk(port)
        sck1.Open()
        '设置界面
        SetUIListen()
    End Sub
按钮退出网络
    Private Sub BExitNet_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BExitNet.Click
        '设置界面
        SetUIWait()
        AppendTxt(TBState, "正在退出网络...")
        '关闭监听
        sck1.Close()
        '设置界面
        SetUIDisconnect()
        AppendTxt(TBState, "已经退出网络")
    End Sub
按钮关闭程序
    Private Sub BClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BClose.Click
        If sck1.State <> CTcpTalk.StateConstants.sckClosed Then
            '关闭监听
            sck1.Close()
            SetUIDisconnect()
        End If
        '退出程序
        Application.Exit()
End Sub
按钮发送
    Private Sub BSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BSend.Click
        '检查参数
        If TBRemote.Text = "" Then
            MsgBox("请输入对方计算机名称或IP")
            TBRemote.Focus()
            Exit Sub
        End If
        If TBPort.Text = "" Then
            MsgBox("请输入端口号")
            Exit Sub
        End If
        Dim port As Long
        Try
            port = CLng(TBPort.Text)
        Catch ex As Exception
            MsgBox("端口号格式错误")
            Exit Sub
        End Try
        '设置远程主机名称和端口
        sck1.RemotePort = port
        sck1.RemoteHost = TBRemote.Text
        '发送数据
        sck1.Send(TBSend.Text)
End Sub
sck1的DataArrival事件
    Private Sub sck1_DataArrival(ByVal bytesTotal As Long) Handles sck1.DataArrival
        AppendTxt(TBRecv, sck1.GetData)
    End Sub
sck1的ErrorEvt事件
    Private Sub sck1_ErrorEvt(ByVal ex As CTcpTalkException) Handles sck1.ErrorEvt
        AppendTxt(TBState, ex.Message)
    End Sub
sck1的Connect事件
    Private Sub sck1_Connect() Handles sck1.Connect
        AppendTxt(TBState, "Connected")
    End Sub
sck1的SendComplete事件
    Private Sub sck1_SendComplete() Handles sck1.SendComplete
        AppendTxt(TBState, "Send Complete")
    End Sub
设置界面(无监听状态)
    Private Sub SetUIDisconnect()
        BJoinNet.Enabled = True
        BExitNet.Enabled = False
        BSend.Enabled = False
    End Sub
设置界面(监听状态)
    Private Sub SetUIListen()
        BJoinNet.Enabled = False
        BExitNet.Enabled = True
        BSend.Enabled = True
    End Sub

设置界面(等待状态)

    Private Sub SetUIWait()
        BJoinNet.Enabled = False
        BExitNet.Enabled = False
        BSend.Enabled = False
    End Sub
向指定文本框添加文本
    Private Sub AppendTxt(ByVal tb As TextBox, ByVal txt As String)
        tb.Text = tb.Text + txt + vbCrLf
End Sub

抱歉!评论已关闭.