使用VB.NET构建客户端/服务器应用程序,实现安全的私有文件共享






3.70/5 (13投票s)
2005年11月24日
7分钟阅读

195949

15608
如何使用免费SDK构建安全的私有文件共享客户端/服务器
引言
如今,大多数加密文件共享解决方案都使用数字证书,这些证书适用于用户群体庞大且事先未知的应用程序。但是,如果有人想避免获取和维护证书的成本和麻烦,那么还有另一种可行的解决方案。
本文介绍了一种用于安全私有文件共享的简单客户端/服务器解决方案。安全性通过对称加密算法(AES 128)和共享密钥来实现。当建立小型群组时,这在许多情况下可能更有效和实用。
开始之前
下载并安装文件共享SDK的免费版本,该版本可免费用于非商业用途(两个连接)。
客户端/服务器组件采用128位AES加密,无需SSL证书。它使用共享密钥,从而创建了一个基于应用程序的虚拟专用网络。除了标准的FTP操作(如上传、下载、重命名、删除等)之外,该库还提供了许多高级功能,如在服务器上打开可查找流、远程搜索文件和文本、远程zip压缩和解压缩。
服务器
加载示例项目FileServer.sln。可以通过其名为FileSrv
的实例来访问服务器组件。让我们回顾一下它的主要属性和方法。
启动服务器
为了开始接受连接,我们需要执行以下步骤
- 将属性
ListenningPort
设置为监听端口号。我们从Settings窗体中获取该值。 - 如果我们要建立加密连接,则必须将属性
SecurityMode
设置为2,并将SecretKey
设置为设置窗体中指定的加密密钥的值。如果我们不需要加密,则必须将
SecurityMode
设置为0。 - 如果我们想使用数据包压缩,则必须将
UseCompression
设置为True
。 - 调用方法
Start()
。'Set the component properties Private Sub SetProperties() FileSrv.ListeningPort = Val(fSettings.txtPort.Text) If fSettings.txtKey.Text > "" Then FileSrv.SecurityMode = 2 'shared secret key FileSrv.SecretKey = fSettings.txtKey.Text Else FileSrv.SecurityMode = 0 'no encryption End If FileSrv.UseCompression = fSettings.chkCompress.Checked End Sub 'Start the server Private Sub btnStart_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnStart.Click If FileSrv.Start Then LogMsg("Server started") Else Call MsgBox("Cannot start the server!", , "Error") End If UpdateStatus() End Sub
停止服务器
为了停止接受连接,我们需要调用方法Stop()
。如果我们当前有客户端连接,则应使用方法RemoveClient()
将其移除。
'Stop the server
Private Sub btnStop_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnStop.Click
Dim LI As ListViewItem
Dim i As Integer
FileSrv.Stop()
For i = lvClients.Items.Count - 1 To 0 Step -1
FileSrv.RemoveClient(lvClients.Items(i).Tag)
lvClients.Items.Remove(lvClients.Items(i))
Next i
UpdateStatus()
LogMsg("Server stopped")
End Sub
添加新连接
当新的客户端连接时,将触发OnNewClient
事件。此时,我们应该获取客户端信息(地址/端口)并将其句柄存储起来以备后用。
'A new connection is available
Private Sub FileSrv_OnNewClient(ByVal sender As Object, _
ByVal e As AxbsFileServerSDK.IBSFileSrvXEvents_OnNewClientEvent) _
Handles FileSrv.OnNewClient
Dim LI As ListViewItem
LI = lvClients.Items.Add("Not signed in")
LI.Tag = e.aHandle
LI.SubItems.Add(FileSrv.GetClientAddress(e.aHandle))
LI.SubItems.Add(Str(FileSrv.GetClientPort(e.aHandle)))
LI.SubItems.Add(VB6.Format(Now, "hh:mm:ss"))
LI.SubItems.Add("Connected")
UpdateStatus()
LogMsg("New connection from " + LI.SubItems.Item(1).Text + _
":" + LI.SubItems.Item(2).Text)
End Sub
移除断开连接的客户端
当已连接的客户端断开连接时,将触发OnClientDisconnected
事件。此时,我们应该释放与该客户端相关的所有数据。
'A connection is broken
Private Sub FileSrv_OnClientDisconnected(ByVal sender As Object, ByVal e As _
AxbsFileServerSDK.IBSFileSrvXEvents_OnClientDisconnectedEvent) _
Handles FileSrv.OnClientDisconnected
Dim LI As ListViewItem
LI = ItemFromHandle(e.aHandle)
If LI Is Nothing Then Exit Sub
LogMsg("Disconnected " + LI.Text + " " + _
FileSrv.GetClientAddress(e.aHandle) + _
":" + Str(FileSrv.GetClientPort(e.aHandle)))
FileSrv.RemoveClient(LI.Tag)
lvClients.Items.Remove(LI)
End Sub
提供用户密码
建立连接后,客户端立即发送登录请求。在我们简单的实现中,我们只接受默认用户(Guest)。因此,在OnNeedPassword
事件的处理程序中,所询问的用户名应始终为空,并且我们始终为密码值传递一个空字符串。
'A request for a password
Private Sub FileSrv_OnNeedPassword1(ByVal sender As Object, ByVal e As _
AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedPasswordEvent) _
Handles FileSrv.OnNeedPassword
If e.aUsername = "" Then
'this is the user Guest
e.aOkay = True
Else
'Unknown user, we accept only Guest
e.aOkay = False
End If
End Sub
登录
在检查密码后,服务器组件将触发OnSignin
事件。从那时起,客户端就可以执行各种文件操作了。
'A user is signed-in
Private Sub FileSrv_OnSignin(ByVal sender As Object, ByVal e As _
AxbsFileServerSDK.IBSFileSrvXEvents_OnSigninEvent) _
Handles FileSrv.OnSignin
Dim S As String
Dim LI As ListViewItem
S = GetUsername(e.aHandle)
LI = ItemFromHandle(e.aHandle)
If Not (LI Is Nothing) Then
LI.Text = S
End If
S = S + " " + FileSrv.GetClientAddress(e.aHandle) + _
":" + FileSrv.GetClientPort(e.aHandle)
If e.aCode = 0 Then
S = S + " signed in successfully"
Else
S = S + " failed sign-in"
End If
LogMsg(S)
End Sub
列出文件夹内容
客户端登录后首先执行的操作是获取(主)文件夹内容。OnNeedListFolder
事件的处理程序负责授予或拒绝操作的权限。有两个输入参数和两个输出参数:
aHandle
- 触发事件的客户端对象的句柄。aPath
- 相关文件夹的相对路径名。aOkay
- 将此变量设置为True
以允许操作。aRoot
- 如果允许操作,请在此处写入分配给该用户的根文件夹。
'A request to list the folder contents
Private Sub FileSrv_OnNeedListFolder(ByVal sender As Object, ByVal e As _
AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedListFolderEvent) _
Handles FileSrv.OnNeedListFolder
e.aOkay = True
e.aRoot = App_Path()
LogMsg(GetUsername(e.aHandle) + ": list folder " + PreSlash(e.aPath))
End Sub
列表操作的结束将通过OnListFolderDone
事件发出信号。
处理“创建文件夹”请求
当从客户端接收到“创建文件夹”请求时,将触发OnNeedCreateFolder
事件。处理程序必须授予或拒绝操作的权限。参数是:
aHandle
- 触发事件的客户端对象的句柄。aPath
- 要压缩的文件的相对路径名。aOkay
- 将此变量设置为True
以允许操作。aRoot
- 如果允许操作,请在此处写入分配给该用户的根文件夹。
'A request to create a folder
Private Sub FileSrv_OnNeedCreateFolder(ByVal sender As Object, ByVal e As _
AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedCreateFolderEvent) _
Handles FileSrv.OnNeedCreateFolder
e.aOkay = True
e.aRoot = App_Path()
LogMsg(GetUsername(e.aHandle) + ": create folder " + PreSlash(e.aPath))
End Sub
处理“重命名文件”请求
当从客户端接收到“重命名文件”请求时,将触发OnNeedRenameFile
事件。处理程序必须授予或拒绝操作的权限。参数是:
aHandle
- 触发事件的客户端对象的句柄。aPath
- 要重命名的文件的相对路径名。aOkay
- 将此变量设置为True
以允许操作。aRoot
- 如果允许操作,请在此处写入分配给该用户的根文件夹。
'A request to rename a file
Private Sub FileSrv_OnNeedRenameFile(ByVal sender As Object, ByVal e As _
AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedRenameFileEvent) _
Handles FileSrv.OnNeedRenameFile
e.aOkay = True
e.aRoot = App_Path()
LogMsg(GetUsername(e.aHandle) + ": rename file " + PreSlash(e.aPath))
End Sub
处理“删除文件”请求
当从客户端接收到“删除文件”请求时,将触发OnNeedDeleteFile
事件。处理程序必须授予或拒绝操作的权限。参数是:
aHandle
- 触发事件的客户端对象的句柄。aPath
- 要删除的文件的相对路径名。aOkay
- 将此变量设置为True
以允许操作。aRoot
- 如果允许操作,请在此处写入分配给该用户的根文件夹。
'A request to delete a file
Private Sub FileSrv_OnNeedDeleteFile(ByVal sender As Object, ByVal e As _
AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedDeleteFileEvent) _
Handles FileSrv.OnNeedDeleteFile
e.aOkay = True
e.aRoot = App_Path()
LogMsg(GetUsername(e.aHandle) + ": delete file " + PreSlash(e.aPath))
End Sub
处理下载请求
当从客户端接收到下载请求时,将触发OnNeedDownload
事件。处理程序必须授予或拒绝操作的权限。参数是:
aHandle
- 触发事件的客户端对象的句柄。aPath
- 要下载的文件的相对路径名。aOkay
- 将此变量设置为True
以允许操作。aRoot
- 如果允许操作,请在此处写入分配给该用户的根文件夹。
'A request to download
Private Sub FileSrv_OnNeedDownload(ByVal sender As Object, ByVal e As _
AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedDownloadEvent) _
Handles FileSrv.OnNeedDownload
e.aOkay = True
e.aRoot = App_Path()
LogMsg(GetUsername(e.aHandle) + ": start downloading " + PreSlash(e.aPath))
End Sub
OnDownloadDone
事件将通知操作的完成。
'The download operation is completed
Private Sub FileSrv_OnDownloadDone(ByVal sender As Object, ByVal e As _
AxbsFileServerSDK.IBSFileSrvXEvents_OnDownloadDoneEvent) _
Handles FileSrv.OnDownloadDone
LogMsg(GetUsername(e.aHandle) + ": finish downloading ")
End Sub
处理上传请求
当从客户端接收到上传请求时,将触发OnNeedUpload
事件。处理程序必须授予或拒绝操作的权限。参数是:
aHandle
- 触发事件的客户端对象的句柄。aPath
- 相关文件的相对路径名。aOkay
- 将此变量设置为True
以允许操作。aRoot
- 如果允许操作,请在此处写入分配给该用户的根文件夹。
'A request to upload
Private Sub FileSrv_OnNeedUpload(ByVal sender As Object, ByVal e As _
AxbsFileServerSDK.IBSFileSrvXEvents_OnNeedUploadEvent) _
Handles FileSrv.OnNeedUpload
e.aOkay = True
e.aRoot = App_Path()
LogMsg(GetUsername(e.aHandle) + ": start uploading " + PreSlash(e.aPath))
End Sub
OnUploadDone
事件将通知操作的完成。
'The upload operation is completed
Private Sub FileSrv_OnUploadDone(ByVal sender As Object, ByVal e As _
AxbsFileServerSDK.IBSFileSrvXEvents_OnUploadDoneEvent) _
Handles FileSrv.OnUploadDone
LogMsg(GetUsername(e.aHandle) + ": finish uploading ")
End Sub
客户端
加载示例项目FileClient.sln。可以通过其名为FileCln
的实例来访问客户端组件。让我们回顾一下它的主要属性和方法。
连接到服务器
为了建立与服务器的新连接,我们需要执行以下步骤:
- 如果我们想要加密连接,则必须将属性
SecurityMode
设置为2,并将SecretKey
设置为“Connect”窗体上指定的加密密钥的值。如果我们不需要加密,则只需将
SecurityMode
设置为0。 - 如果我们想使用数据包压缩,则必须将属性
UseCompression
设置为True
。 - 调用方法
Connect(Addr, Port)
,并将服务器的IP地址/域名和监听端口作为参数传递。'Initiate a connection request Private Sub btnConnect_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnConnect.Click If fConnect.ShowDialog <> DialogResult.OK Then Exit Sub If fConnect.txtKey.Text() > "" Then FileCln.SecurityMode = 2 'shared secret key FileCln.SecretKey = fConnect.txtKey.Text Else FileCln.SecurityMode = 0 ' no encryption End If If Not FileCln.Connect(fConnect.txtHost.Text, _ Val(fConnect.txtPort.Text)) Then MsgBox("Error Code: " + Str(FileCln.LastError)) End If UpdateStatus() End Sub
与服务器断开连接
为了结束与服务器的连接,我们需要调用方法Disconnect()
。
'Disconnect from the server
Private Sub btnDisconnect_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnDisconnect.Click
If Not FileCln.Connected Then Exit Sub
FileCln.Disconnect()
Call DoDisconnected()
End Sub
列出文件夹内容
方法ListFolder()
发送一个请求以获取文件夹内容。
'Request the folder contents
Private Sub ListFolder()
If NowList Then Exit Sub
If FileCln.ListFolder(txtFolder.Text) Then
NowList = True
lvFiles.Items.Clear()
btnList.Enabled = False
If txtFolder.Text > "\" Then
Call DoHaveListItem("..", True, 0, 0, 0, 0)
End If
Else
CheckError(FileCln.LastError)
End If
End Sub
对于每个可用的文件夹项,将触发OnHaveListItem
事件。
'Process a list item
Private Sub DoHaveListItem(ByVal aName As String, _
ByVal aFolder As Boolean, ByVal aLoSize As Long, _
ByVal aHiSize As Long, _
ByVal aLoTime As Long, ByVal aHiTime As Long)
Dim LI As ListViewItem
Dim ft As FILETIME
Dim Dt As Date
LI = lvFiles.Items.Add(aName)
If aFolder Then
LI.ImageIndex = FolderImgIdx
LI.SubItems.Add(" ")
Else
LI.ImageIndex = FileImgIdx
LI.SubItems.Add(Str(aLoSize))
End If
ft.dwHighDateTime = aHiTime
ft.dwLowDateTime = aLoTime
Dt = FileTimeToDate(ft)
LI.SubItems.Add(Dt)
End Sub
列表的结束将通过OnListFolderDone()
事件发出信号。
'End of the list
Private Sub FileCln_OnListFolderDone(ByVal sender As Object, ByVal e As _
AxbsFileClientSDK.IBSFileClnXEvents_OnListFolderDoneEvent) _
Handles FileCln.OnListFolderDone
NowList = False
'CheckError(aCode)
UpdateButtons()
End Sub
创建新文件夹
方法CreateFolder()
发送一个请求来创建一个新文件夹。
'Request a new folder
Private Sub btnNew_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnNew.Click
Dim Nm As String
Nm = InputBox("Folder name:", "Create folder")
If Nm = "" Then Exit Sub
If FileCln.CreateFolder(AddSlash(txtFolder.Text) + Nm) Then
NowCreate = True
Else
CheckError(FileCln.LastError)
End If
UpdateButtons()
End Sub
文件夹创建完成后,将触发OnCreateFolderDone()
事件。
'A new folder is created
Private Sub FileCln_OnCreateFolderDone(ByVal sender As Object, ByVal e As _
AxbsFileClientSDK.IBSFileClnXEvents_OnCreateFolderDoneEvent) _
Handles FileCln.OnCreateFolderDone
NowCreate = False
CheckError(e.aCode)
UpdateButtons()
If e.aCode > 0 Then Exit Sub
Call ListFolder()
End Sub
重命名文件
方法RenameFile()
发送一个请求以在服务器上重命名文件。
'Send rename request
Private Sub btnRename_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnRename.Click
Dim Nm As String
If lvFiles.SelectedItems.Count = 0 Then Exit Sub
If lvFiles.SelectedItems(0).ImageIndex = FolderImgIdx Then
'it is a folder
Nm = InputBox("New name:", "Rename folder")
If Nm = "" Then Exit Sub
If FileCln.RenameFolder(AddSlash(txtFolder.Text) + _
lvFiles.SelectedItems(0).Text, _
AddSlash(txtFolder.Text) + Nm) Then
NowRenameFolder = True
Else
CheckError(FileCln.LastError)
End If
Else
'it is a file
Nm = InputBox("New name:", "Rename file")
If Nm = "" Then Exit Sub
If FileCln.RenameFile(AddSlash(txtFolder.Text) + _
lvFiles.SelectedItems(0).Text, _
AddSlash(txtFolder.Text) + Nm) Then
NowRenameFile = True
Else
CheckError(FileCln.LastError)
End If
End If
Call UpdateButtons()
End Sub
收到确认后,将触发OnRenameFileDone()
事件。
'A file is renamed
Private Sub FileCln_OnRenameFileDone(ByVal sender As Object, ByVal e As _
AxbsFileClientSDK.IBSFileClnXEvents_OnRenameFileDoneEvent) _
Handles FileCln.OnRenameFileDone
NowRenameFile = False
CheckError(e.aCode)
Call UpdateButtons()
If e.aCode > 0 Then Exit Sub
Call ListFolder()
End Sub
删除文件
方法DeleteFile()
发送请求以删除文件。
'Send delete request
Private Sub btnDelete_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnDelete.Click
If lvFiles.SelectedItems.Count = 0 Then Exit Sub
If lvFiles.SelectedItems(0).ImageIndex = FolderImgIdx Then
'it is a folder
If FileCln.DeleteFolder(AddSlash(txtFolder.Text) + _
lvFiles.SelectedItems(0).Text) Then
NowDeleteFolder = True
Else
CheckError(FileCln.LastError)
End If
Else
'it is a file
If FileCln.DeleteFile(AddSlash(txtFolder.Text) + _
lvFiles.SelectedItems(0).Text) Then
NowDeleteFile = True
Else
CheckError(FileCln.LastError)
End If
End If
Call UpdateButtons()
End Sub
收到确认后,将触发OnDeleteFileDone()
事件。
'A file is deleted
Private Sub FileCln_OnDeleteFileDone(ByVal sender As Object, ByVal e As _
AxbsFileClientSDK.IBSFileClnXEvents_OnDeleteFileDoneEvent) _
Handles FileCln.OnDeleteFileDone
NowDeleteFile = False
CheckError(e.aCode)
Call UpdateButtons()
If e.aCode > 0 Then Exit Sub
Call ListFolder()
End Sub
下载文件
方法Download()
发送一个请求以下载文件。
'Send download request
Private Sub GoDownload()
If lvFiles.SelectedItems.Count = 0 Then Exit Sub
If lvFiles.SelectedItems(0).ImageIndex = FolderImgIdx Then
Exit Sub
SaveDlg.FileName = lvFiles.SelectedItems(0).Text
If SaveDlg.ShowDialog() <> DialogResult.OK Then Exit Sub
DnldFile = lvFiles.SelectedItems(0).Text
If FileCln.Download(AddSlash(txtFolder.Text) + _
lvFiles.SelectedItems(0).Text, _
ExtractFilePath(SaveDlg.FileName)) Then
NowDownload = True
txtDownload.Text = DnldFile + ": handshaking"
Else
CheckError(FileCln.LastError)
End If
UpdateStatus()
End Sub
OnDownloadProgress()
事件将通知下载进度。
'Download progress info
Private Sub FileCln_OnDownloadProgress(ByVal sender As Object, ByVal e As _
AxbsFileClientSDK.IBSFileClnXEvents_OnDownloadProgressEvent) _
Handles FileCln.OnDownloadProgress
txtDownload.Text = DnldFile + " - " + _
Str(e.aCountLo) + "/" + Str(e.aSizeLo)
End Sub
下载完成后,将触发OnDownloadDone()
事件。
'The download is completed
Private Sub FileCln_OnDownloadDone(ByVal sender As Object, _
ByVal e As AxbsFileClientSDK.IBSFileClnXEvents_OnDownloadDoneEvent) _
Handles FileCln.OnDownloadDone
If e.aCode = 0 Then
txtDownload.Text = DnldFile + " - Done."
Else
txtDownload.Text = DnldFile + " - Aborted: " + ErrorText(e.aCode)
End If
NowDownload = False
Call UpdateButtons()
End Sub
上传文件
方法Upload()
发送一个请求以上传文件。
'Send upload request
Private Sub btnUpload_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnUpload.Click
On Error GoTo IsCanceled
OpenDlg.FileName = ""
If OpenDlg.ShowDialog() <> DialogResult.OK Then Exit Sub
UpldFile = OpenDlg.FileName
If FileCln.Upload(UpldFile, txtFolder.Text) Then
NowUpload = True
UpldFol = txtFolder.Text
txtUpload.Text = ExtractFileName(UpldFile) + ": handshaking"
Else
CheckError(FileCln.LastError)
End If
UpdateStatus()
IsCanceled:
End Sub
OnUploadProgress()
事件将提供有关上传进度的信息。
'Upload progress info
Private Sub FileCln_OnUploadProgress(ByVal sender As Object, _
ByVal e As AxbsFileClientSDK.IBSFileClnXEvents_OnUploadProgressEvent) _
Handles FileCln.OnUploadProgress
txtUpload.Text = ExtractFileName(UpldFile) + " - " + _
Str(e.aCountLo) + "/" + Str(e.aSizeLo)
End Sub
上传操作完成后,将触发OnUploadDone()
事件。
'The upload is completed
Private Sub FileCln_OnUploadDone(ByVal sender As Object, _
ByVal e As AxbsFileClientSDK.IBSFileClnXEvents_OnUploadDoneEvent) _
Handles FileCln.OnUploadDone
If e.aCode = 0 Then
txtUpload.Text = ExtractFileName(UpldFile) + " - Done."
Else
txtUpload.Text = ExtractFileName(UpldFile) + _
" - Aborted: " + ErrorText(e.aCode)
End If
NowUpload = False
Call UpdateButtons()
If UpldFol = txtFolder.Text Then
Call ListFolder()
End If
End Sub
底线
如今,由于各种原因,互联网是不安全的。在许多情况下,交换敏感信息可能是一个问题。在本文中,我们介绍了一种简单且经济实惠的解决方案,用于安全私有文件共享,而无需证书。