Internet协议窥视器
王 飞
Internet的应用层,是由一对对客户机与服务器构成的,要想在其上开发新的应用,充分了解客户机与服务器之间的通信协议是非常重要的。这里向大家介绍一个小程序,能够容易地弄清楚这些协议,深入到Internet的应用中。
在Internet上进行数据传输,无外通过TCP或UDP两种方式,首先是客户机根据服务器的IP地址及端口号呼叫主机,在服务器应答后数据传输就开始了,数据传输的格式和次序,就是我们所要了解的协议,可以用下图来示意这一过程:
如果在客户机与服务器之间,插入一个自制的程序,用它来充当原先客户机的服务器,充当原先服务器的客户机,那么原来两个程序之间的数据通信,就通过这个程序进行中转。在中转过程中,让这个自制的程序保存一份数据,“协议窥视器”就算实现了,就像下图示意的一样:

现在我们就开始具体的设计,我使用的语言是VB5。程序的主要任务是模拟成一个服务器程序,等待客户机程序的呼叫,当接收到客户机程序的请求数据后,原封不动地发送给真正的服务器程序;当收到服务器程序发回的应答数据时,照样原封不动地传送给客户机程序。这一过程一直持续,直到有一方终止了连接(这里只就TCP方式进行设计,至于UDP的情况基本差不多)。另外就是将所有接收到的数据,都保存到磁盘文件中。为完成上述过程,需要几个已知变量,它们是:
>
′本地主机地址及端口,提供给客户机程序进行连接
Public lHost As String, lPort As Long
′远程主机地址及端口,也就是原服务器程序
Public rHost As String, rPort As Long
′保存数据文件的路径
Public LogFilePath As String
不管用什么样的方法,在程序的开始,都要将这五个变量赋予正确的值。接下来设计一个专门处理收发数据的窗体(Form),它要同时连接客户机程序和服务器程序,所以窗体上需要两个Winsock控件,分别名命为“sock—c”、“sock—s”,这个窗体不必显示出来,它通过一个初始化函数来启动:
Public Sub Init(ByVal requestID As Long)
sock—c.Accept requestID
DoEvents
sock—s.Connect rHost, rPort
End Sub
这个函数完成两件事:接受客户机程序的连接请求,并向服务器程序发出连接请求。这个函数之后,就会分别产生两个Winsock控件的Connect事件,通知连接成功。再之后就会在DataArrival事件中收到来自双方的数据,按照我们的设想,在这时将数据先保存到文件中,再转发给对方:
Private Sub sock—c—DataArrival(ByVal bytesTotal As Long)
Dim D() As byte
Sock—c.GetData D, vbArray + vbByte, bytesTotal
SaveDataToFile D
Sock—s.SendData D
End Sub
Private Sub sock—s—DataArrival(ByVal bytesTotal As Long)
Dim D() As byte
Sock—s.GetData D, vbArray + vbByte, bytesTotal
SaveDataToFile D
Sock—c.SendData D
End Sub
最后,在接到任何一方的Close或Error事件时,结束这一窗体。这个窗体很有点接近代理服务器的功能,所以我把它命名为:frmProxy。
实现这一数据收发的窗体后,剩下的是还需要一个“请求侦听”窗体,它只需要一个Winsock控件,把它命名为“sock”,另外为了了解运行情况,不妨可以加上一个显示状态信息之类的控件,在这个窗体开始时,要将Winsock设置为侦听状态:
Private Sub Form—Load()
sock.Bind lPort, lHost ′邦定在已知的本地主机地址和端口上
sock.Listen ′开始侦听
End Sub
每当产生一个连接请求时,就生成一个数据收发窗体来进行响应,并继续侦听下一个连接请求:
Private Sub sock—ConnectionRequest(ByVal requestID As Long)
Dim frm As New frmProxy ′ 新建一个数据收发窗体
frm.sock—d.Init requestID ′ 启动窗体响应连接请求
End Sub
到这里整个程序的主要框架就完成了,不过要提醒一点:上面描述的数据收发窗体,存在一个异步问题没有解决,在实际设计时,这个问题不可忽略,应作为一个难点仔细考虑。