无公网IP,VB应用从外网访问内网服务器


  1. 应用需求

    之前做的板子加密工具,需要客户在工厂将所有板子先扫描一遍,然后将扫描得到的结果文件通过邮件发送给开发人员。开发人员根据收到的数据文件,生成一个加密文件,并发回给工厂。工厂收到加密数据后,需要重新扫描所有板子,将加密数据写入对应的板子。这样做的结果是需要工厂对所有板子操作两遍,中间还需要等待接收邮件,比较麻烦和费时。

    新的设想是,工厂在扫描每片板子时,即时通过互联网将数据发送到开发人员架设的服务器,服务器收到数据后,对数据进行加密后回传。扫描工具得到回传数据后,立即将加密数据烧入板子,完成对板子的加密。

    这样做的好处是,工厂只需要对所有板子操作一遍即可。虽然其中也有收发数据,但是收发数据完全是自动的,对操作人员来说,就像没有发生一样。操作人员只需要将串口连接上板子,在工具上点击一次加密即可,几秒钟就可以完成一片板子的加密。这样就比较简单了。

     

  2. 软件编写

    工具软件采用VB编写,工厂端的软件为客户端,开发端的软件为服务器。因条件所限,开发端的服务器处在内网中(移动光宽带),出口无公网IP

     

    1、服务器编写简述:

    新建一个VB工程,添加 Microsoft Winsock Control6.0 部件。添加该部件后,就可以在窗体上添加一个Winsock控件,命名为sckServer。在窗体load时,需要设置本地端口号(用于监听客户端的连接请求),然后启用端口监听。代码如下:

    Private Sub Form_Load()

       intMax = 0

       sckServer(0).LocalPort = 12345

       txtServerIP.Text =sckServer(0).LocalIP  仅用于显示本地IP,如192.168.100.22

       sckServer(0).Listen

    End Sub

     

    当客户端发起连接请求后,服务器端会产生_ConnectionRequest事件。在该事件中可以处理接受连接请求:

    Private Sub sckServer_ConnectionRequest(Index As Integer, ByValrequestID As Long)

       If Index = 0 Then

          intMax = intMax + 1

          Load sckServer(intMax)

          sckServer(intMax).LocalPort= 0

          sckServer(intMax).AcceptrequestID

       End If

    End Sub

     

    一旦客户端和服务器端建立连接后,客户端发送数据后,服务器端会产生_DataArrival事件,服务器端可以在这里检查数据是否合法,并对数据加密后回传给客户端。

    Private Sub sckServer_DataArrival(Index As Integer, ByVal bytesTotalAs Long)

        Dim MyStr As String

    sckServer(Index).GetData MyStr

    If CheckMyStr =True Then

            Process(MyStr)

            sckServer(Index).SendData  MyStr     回传加密后的数据

        End If

    End Sub

     

    1、客户端编写简述:

    同样,新建一个VB工程,添加Microsoft Winsock Control6.0 部件。添加该部件后,在窗体上添加一个Winsock控件,命名为WinsockClient。窗体上放置一个Command按钮,命名为cmdConnect,用于连接服务器。点击该按钮后,产生_Click事件,在其中处理连接过程:

     

    Private Sub cmdConnect_Click()

        Dim SendTime As Single,PreTime As Single

        'Print txtServerIP.Text

                          WinsockClient.Close

            需要先输入服务器地址,

            If txtServerIP.Text = "xxxx.nat123.cc"Then

    '从外网xxxx.nat123.cc54333 通过nat123访问,映射到内网192.168.100.2212345

                WinsockClient.RemotePort= 54333   

            Else

               WinsockClient.RemotePort = 12345   '从局域网内访问,不需转换

            End If

           WinsockClient.RemoteHost = txtServerIP.Text

           WinsockClient.Connect 

     

            NetStatus = False                       '置标志

            SendTime =Timer()                      '取发送时刻

            Do While Timer() <SendTime + 10        '最大等待10

                If NetStatus =True Then

                    Exit Do

                End If

                DoEvents

            Loop

       

            '显示连接结果

            If NetStatus = TrueThen

                MsgBox "已连接到服务器", vbInformation

            Else

               WinsockClient.Close

                MsgBox "连接服务器超时", vbInformation

            End If

    End Sub

     

    在上面这个函数中,主要要给出客户端需要连接的服务器的IP地址和端口。如果客户端和服务器处在同一内网中,则只要将服务器的IP地址和监听的端口赋给客户端的remote属性即可,在内网中用例如下:

           WinsockClient.RemotePort = 12345        

           WinsockClient.RemoteHost = 192.168.100.22

            WinsockClient.Connect

    如果客户端是外网连接服务器,则需要更改如下(以nat123穿透内网为例):

           WinsockClient.RemotePort = 54333                 

           WinsockClient.RemoteHost = xxxx.nat123.cc

            WinsockClient.Connect

    这里 xxxx.nat123.cc 54333 是在nat123 上设置端口映射时,由nat123自动赋予的,不能随便更改。

     

    当客户端调用WinsockClient.Connect后,服务器端就会产生sckServer_ConnectionRequest事件。然后服务器端调用sckServer(intMax).AcceptrequestID,接收连接请求,这时,客户端就会产生WinsockClient_Connect() 事件,表示连接成功。因此在该事件中,客户端可以设置连接成功标志。

     

    Private Sub WinsockClient_Connect()

        NetStatus = True

    End Sub

     

    以上代码在内网中测试没有问题。但是当客户端在外网中发起连接时,此时即使服务器端没有启动,在客户端仍会产生WinsockClient_Connect()事件。因为在外网情况下,客户端的数据是发往 nat123 服务器的,然后nat123 再将数据转发给内网的服务器。不管内网的服务器是否启动,正常情况下,客户端和nat123 之间的连接是成功的。如果nat123 到服务器的连接不通,则nat123会返回一些错误代码给客户端,所以从客户端来看,连接是成功的,并会接收到许多数据。

     

    解决以上问题的方法是,在WinsockClient_Connect() 中不能立即判断为连接成功,而是发送一个特定的握手数据给服务器,服务器端收到握手数据后,立即返回一个特定的确认数据。当客户端收到确认数据后,才能确定连接是真正成功的。代码修改如下:

    Private Sub WinsockClient_Connect()

        '在这里发出一个握手信号给服务器

        WinsockClient.SendData"发送指定字符串"

    End Sub

     

    在接收数据事件中判断回复数据:

    Private Sub WinsockClient_DataArrival(ByVal bytesTotal As Long)

        Dim MyStr As String

        WinsockClient.GetDataMyStr

       

        If MyStr = "回复指定字符串" Then

            '连接后,收到服务器端发来的握手信号,才表示真的连接上了

            NetStatus = True

        Else

            '检查数据是否有server签名,如果是,则当作正常的加密数据,写入板子

                   不是,则不必处理

        End If

    End Sub

     

  3. 内网测试:

    软件写好后,首先在内网中测试:

    首先启动服务器,等待客户端连接:

     

    然后启动客户端:

     

    点击“未连接”按钮后,可以看到连接成功。在输入框中输入字符”test”后,点击发送,可以看到服务器中显示接收到一样的字符串,并在前面添加“reply:” 后,再回传给客户端,客户端这边也有显示收到的回传数据。截图如下:

     

    如上图表示,在内网中,客户端和服务器之间的连接、数据收发是成功的。

     

     

  4. 外网测试

    内网测试成功后,就需要进行外网测试。

    将客户端软件复制到另外一台电脑中,该电脑使用无线网卡,连接手机上的wifi热点上网,模拟外网的环境。

    服务器仍然在内网中,通过移动提供的HG8245路由器连接移动光宽带。

     

    在没有采用NAT123 之前,从网上找了许多外网访问内网的帖子看,在华为HG8245路由器的管理页面里也反复尝试了DMZ主机和端口映射,都没有成功,客户端始终不能连接到服务器。

     

    另外用IP地址查询到本机IP地址和路由器上显示的IP地址也不一致,看了网帖,明白这个似乎是没有公网IP的,移动将路由器又映射了一次,IP地址查看到的是移动的公网IP,路由器上看到的相当于是内网IP。截图如下:

     

  5. Nat123 安装和使用

    折腾了几天没有结果,看到网帖上有用nat123 做内网端口映射的,于是上nat123 的官网上看了一下。

    Nat123 官网:http://www.nat123.com/

    首先要注册,截图如下:

     

    然后下载windows版整合运行环境安装包http://www.nat123.com/Pages_2_32.jsp

    下载的安装包名为nat123_V1.160421_NET4.zip,在内网服务器所在电脑里解压后安装,需要好几分钟。

     

    运行nat123的客户端,界面是这样的:

    注意,没有添加映射之前,图中是没有那个蝴蝶图案的。

     

    登录后,点击添加映射,按下图设置后,点击保存即可:

     

    在这里,充值8元钱,完成实名认证后,才可以保存。保存后系统就不断刷新,直到出现前图中的彩色蝴蝶,就表示映射成功了。

     

    映射成功后,启动服务器。在另一台模拟外网的电脑上运行客户端,点击连接测试,发现可以连接到服务器了。截图如下:

     

     

     

     

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭