TCP/IP文鍵傳輸系統
一、設計原理
1.1伺服器
1.需求分析
(1)自定義金鑰數字,自定義埠,建立套接字字
(2)監聽,斷開監聽
(3)顯示接入的使用者
(4)收檔案
自動接受並將檔案儲存到當前的文件中,並將檔名、大小、傳送者的IP存入目錄中
(5)發文件
收到客戶機請求後,自動傳送檔案,無需人工操作
2.邏輯設計
1.先監聽。收到使用者的連線後,將客戶的資訊存到客戶目錄中
2.收到客戶的檔案傳送請求後,準備接收檔案。收到檔案後把檔案資訊存到檔案目錄中。檔案存到當前文件中
3.收到客戶的目錄傳送請求後,傳送檔案數量,迴圈傳送檔案目錄中的檔案資訊。
4.收到客戶的檔案下載請求後,準備接收檔案資訊。收到檔案資訊後,找到相應檔案傳送過去。
3.類和關鍵函式的設計
-
Page1和Page2是用來儲存檔案資訊表和客戶資訊表的兩個對話方塊,在伺服器對話方塊的Tab Control控制元件裡。
-
MySocket就是類似於第十章的MySocket.
OnAccept()函式作用就是當連線了客戶後,將客戶資訊載入到客戶資訊裡。令客戶端的choice為0,表示客戶端剛連線上
3.,CClientSocket就是類似於第十章的NewSocket,主要用於存客戶機資訊。
choice(int)用來儲存客戶機的請求資訊。0:客戶端連線上了,準備傳送金鑰數字1:客戶端傳送檔案 2:客戶端請求檔案目錄 3:客戶端請求傳送檔案。
Askingwfd (WIN32_FIND_DATA) 用來儲存客戶機需要下載的檔案資訊。
OnReceive() 先來接收客戶機的請求資訊choice 。客戶端傳送檔案時,先接收檔案的資訊。然後分批接受儲存。如果成功接收,就將資訊儲存到檔案目錄。請求檔案目錄時,就轉到OnSend()。客戶端請求檔案下載時,就接收檔案資訊Askingwfd然後轉到OnSend()
OnSend(),判斷客戶機的請求資訊choice。客戶端剛連線上,傳送金鑰數字。客戶端請求檔案目錄,就傳送檔案數量,然後迴圈傳送檔案資訊。
客戶端請求下載檔案時,根據收到的檔案資訊Askingwfd來找到檔案併發送
1.2客戶機
1.需求分析
1.輸入伺服器的IP地址和埠號後連線。
2.登入,登出
3.傳送檔案
4.登入後可以瀏覽伺服器的檔案資訊
5.得到伺服器檔案資訊後,可以選擇下載。
2.邏輯設計
1.先連線,連線後收到金鑰數字。
2.傳送檔案。先發送傳送檔案的請求,然後傳送檔案資訊。最後傳送檔案
3.登入。如果密碼和收到的金鑰數字一樣,則登入成功,然後登出、瀏覽檔案、下載這些 按鈕才可用,檔案目錄才可見。
4.瀏覽伺服器檔案。傳送瀏覽伺服器檔案目錄的請求後,準備接收檔案數量,然後迴圈接收檔案資訊,並存儲檔案資訊。把檔案資訊顯示在目錄中。
5.下載。從檔案目錄中選擇檔案後,傳送檔案下載請求。然後將對應的檔案資訊傳送過去,然後準備接收檔案。檔案儲存再當前目錄。
3.類和關鍵函式的設計
FileListDlg是儲存伺服器檔案資訊的。LoginDlg是登陸對話方塊。MySocket,是CSocket的子類,類似於第十章的MySocket
1.C客戶端Dlg
OnInitDialog()初始化,只有連線伺服器按鈕可用。套接字的choice(in)表示,服務種類。0:初始化,收到登陸金鑰 1:傳送檔案 2:請求伺服器檔案目錄 3:請求下載。
(按鈕)連線伺服器:OnBnClickedconnectbtn()。令套接字的choice為0,表示初始化。成功連線後。才可以使用瀏覽、傳送、斷開連線、登入按鈕。
(按鈕)登入:OnBnClickedLogin()。顯示登入對話方塊,只用密碼和伺服器設定的金鑰相同,才登陸成功,然後可以使用瀏覽伺服器檔案、下載、登出按鈕。顯示檔案目錄/同時登入按鈕設定為不可用。
(按鈕)下載:OnBnClickedDownload()。choice=3.當選擇了檔案目錄的某一條後,才可以下載。
(按鈕)登出:OnBnClickedLogin()。檔案目錄不可見。設定登入按鈕可用,瀏覽伺服器檔案、傳送、登出按鈕不可用。
2.MySocket。和第十章的MySockey類似,客戶端套接字
deFile(deque< WIN32_FIND_DATA>) :儲存伺服器發來的檔案目錄星系
choice(int):表示服務型別,上文提到了。
OnReceive:choice=0。表示初始化,接收伺服器發來的金鑰數字,用來判斷登入密碼的正確性。choice=2時,先清空當前的檔案目錄資訊和目錄顯示,然後接收伺服器發來的檔案資訊,並顯示。choice=3時,接收伺服器發來的檔案。
二、設計步驟
2.1伺服器
2.1.1. 初始化 C伺服器Dlg::OnInitDialog()
初始化兩個目錄。檔案目錄和客戶端目錄
BOOL C伺服器Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 設定此對話方塊的圖示。 當應用程式主視窗不是對話方塊時,框架將自動
// 執行此操作
SetIcon(m_hIcon, TRUE); // 設定大圖示
SetIcon(m_hIcon, FALSE); // 設定小圖示
// TODO: 在此新增額外的初始化程式碼
//為Tab Control增加兩個頁面
//----------------------初始化兩個目錄-------------------------------//
MyTab.InsertItem(0, _T("檔案"));
MyTab.InsertItem(1, _T("客戶端"));
m_pSocket = new MySocket;
//m_pSocket->ps = new CClientSocket;
//關聯對話方塊,並且將IDCTABTEST控制元件設為父視窗
mPage1.Create(IDD_PAGE1, GetDlgItem(IDC_TAB1));
mPage2.Create(IDD_PAGE2, GetDlgItem(IDC_TAB1));
//獲得IDC_TABTEST客戶區大小
CRect rs;
MyTab.GetClientRect(&rs);
//調整子對話方塊在父視窗中的位置
rs.top += 30;
rs.bottom -= 60;
rs.left += 1;
rs.right -= 2;
//設定子對話方塊尺寸並移動到指定位置
mPage1.MoveWindow(&rs);
mPage2.MoveWindow(&rs);
//分別設定隱藏和顯示
mPage1.ShowWindow(true);
mPage2.ShowWindow(false);
//設定預設的選項卡
MyTab.SetCurSel(0);
mPage2.m_ClientList.InsertColumn(0, _T("IP地址"), LVCFMT_LEFT,200);
mPage2.m_ClientList.InsertColumn(1, _T("埠"), LVCFMT_LEFT,150);
mPage1.m_FileList.InsertColumn(0, _T("檔名"), LVCFMT_LEFT, 100);
mPage1.m_FileList.InsertColumn(1, _T("檔案大小"), LVCFMT_LEFT, 100);
mPage1.m_FileList.InsertColumn(2, _T("傳送方IP地址"), LVCFMT_LEFT, 200);
//GetDlgItem(IDC_BtnConnect)->EnableWindow(false);
GetDlgItem(IDC_disBtn)->EnableWindow(false);
return TRUE; // 除非將焦點設定到控制元件,否則返回 TRUE
}
2.1.2. 監聽按鈕 C伺服器Dlg::OnBnClickedBtnconnect()
1.建立套接字
編輯框輸入,設定為值 iPort。但是由於文字框的重新整理問題,文字框的值很難傳遞進來,所以我用的是直接去文字框內值的辦法。IDC_EDIT1是編輯框的ID。
int i = GetDlgItemInt(IDC_EDIT1);
建立的CSocket子類MySocket。又MySocket* m_pSocket來連線套接字。本來是準備用第十章講的CAsyncSocket來建立,後來看網上的教學視訊是用的CSocket,查了一下好像是封裝後的,更簡單。
if (FALSE == m_pSocket->Create(i, SOCK_STREAM))
{
MessageBox(_T("套接字創立失敗,換一個埠"));
return;
}
2.監聽,監聽失敗
if (FALSE == m_pSocket->Listen())
{
MessageBox(_T("監聽失敗"));c++
return;
}
3.傳入金鑰數字。為了防止誤操,設定金鑰數字編輯框和監聽按鈕不可用。
KeyWord = GetDlgItemInt(IDC_KeyWordEdt);
GetDlgItem(IDC_KeyWordEdt)->EnableWindow(false);
GetDlgItem(IDC_BtnConnect)->EnableWindow(false);
GetDlgItem(IDC_disBtn)->EnableWindow(true);
2.1.3 斷開監聽 C伺服器Dlg::OnBnClickeddisbtn()
斷開監聽。並設定金鑰編輯框和監聽按鈕可用。
closesocket(sListen);
WSACleanup();c+
GetDlgItem(IDC_BtnConnect)->EnableWindow(true);c++
GetDlgItem(IDC_disBtn)->EnableWindow(false);
GetDlgItem(IDC_KeyWordEdt)->EnableWindow(true);
2.1.4連線上客戶端 MySocket::OnReceive(int nErrorCode)
1.連線後,將對應客戶端的choice初始化為0,準備傳送金鑰數字
ps = new CClientSocket;
Accept(*ps);
ps->GetPeerName(IpAddr,uPort);
ps->choice = 0;
ps->AsyncSelect(FD_WRITE);
2.記錄客戶端資訊到客戶目錄裡。
C伺服器Dlg* pMainDlg = (C伺服器Dlg*)AfxGetMainWnd();
pMainDlg->mPage2.m_ClientList.InsertItem(0, IpAddr);
CString str;
str.Format(_T("%d"), uPort);
pMainDlg->mPage2.m_ClientList.SetItemText(0,1, str);
pMainDlg->mPage2.m_ClientList.SetItemData(0,(DWORD)ps);
2.1.4 接收客戶端的內容 CClientSocket::OnReceive(int nErrorCode)
1.接收客戶端的請求
Receive(&choice, sizeof(choice));
2.choice==1。客戶端請求上傳檔案到伺服器
接收檔案資訊,並且在當前資料夾創造檔案,準備接受。
if (choice == 1)//客戶端上傳檔案
{
C伺服器Dlg* pMainDlg = (C伺服器Dlg*)AfxGetMainWnd();
WIN32_FIND_DATA wfd;
Receive(&wfd, sizeof(wfd),0);
CString str;
CFile file;
if (FALSE == file.Open(wfd.cFileName, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary))
{
OutputDebugString(_T("檔案開啟失敗"));
return;
}
迴圈接收檔案內容,直到接收完成。當接受內容等於檔案大小時,表示接受完成
DWORD dwReadCount = 0;
//迴圈收檔案內容
while (dwReadCount < wfd.nFileSizeLow)
{
char* buffer = new char[1024];
int n;
n=Receive(buffer, 1023);
buffer[n] = '\0';
dwReadCount += n;
OutputDebugString(_T("2"));
file.Write(buffer, n);
delete[] buffer;
}
記錄檔案資訊到檔案目錄內
pMainDlg->mPage1.m_FileList.InsertItem(0, wfd.cFileName);
str.Format(_T("%d"), wfd.nFileSizeLow);
pMainDlg->mPage1.m_FileList.SetItemText(0, 1, str);
pMainDlg->mPage1.m_FileList.SetItemText(0, 2, IpAddr);
}
3.choice==2.準備傳送對應內容
else if (choice == 2)//客戶端請求檔案目錄
{
AsyncSelect(FD_WRITE);
}
4.choice==3.接收客戶端需要下載的檔案資訊Askingwfd,準備傳送對應內容
else if (choice == 3)//客戶端請求檔案
{
Receive(&Askingwfd, sizeof(Askingwfd), 0);
AsyncSelect(FD_WRITE);
}
2.1.5 傳送內容到客戶端 CClientSocket::OnSend(int nErrorCode)
通過choice判斷客戶端的請求
choice為0,剛連線上客戶端,傳送金鑰數字。準備接收服務請求
if (choice == 0)
{
C伺服器Dlg* pMainDlg = (C伺服器Dlg*)AfxGetMainWnd();
CString str;
int kWord = pMainDlg->KeyWord;
Send(&kWord, sizeof(kWord));
str.Format(_T("%d"), pMainDlg->KeyWord);
OutputDebugString(str);
AsyncSelect(FD_READ);
}
choice為2。客戶端請求檔案目錄。先發送目錄大小,然後迴圈找到對應的檔案,傳送檔案資訊。
if (choice == 2)//客戶端請求檔案目錄
{
C伺服器Dlg* pMainDlg = (C伺服器Dlg*)AfxGetMainWnd();
//OutputDebugString(_T("有人請求目錄"));
WIN32_FIND_DATA wfd;
int sum = pMainDlg->mPage1.m_FileList.GetItemCount();
Send(&sum, sizeof(sum));
for (int i = 0; i < sum; i++)
{
HANDLE hFinder = FindFirstFile(pMainDlg->mPage1.m_FileList.GetItemText(i, 0), &wfd);
FindClose(hFinder);
Send(&wfd, sizeof(wfd),0);
}
OutputDebugString(_T("傳送完成"));
AsyncSelect(FD_READ);
}
choice為3。客戶端請求檔案下載。通過接收到的檔案資訊Askingwfd,找到對應檔案併發送
if (choice == 3)
{
CFile file;
if (FALSE == file.Open(Askingwfd.cFileName, CFile::modeRead | CFile::typeBinary))
{
//MessageBox("檔案開啟失敗");
return;
}
DWORD dwReadCount = 0;
char* buffer = new char[1024];
int n = 0;
while (dwReadCount < Askingwfd.nFileSizeLow)
{
memset(buffer, 0, sizeof(buffer));
n = file.Read(buffer, 1023);
buffer[n] = '\0';
Send(buffer, n);
dwReadCount += n;
}
delete[]buffer;
AsyncSelect(FD_READ);
}
2.2客戶端
2.2.1初始化 C客戶端Dlg::OnInitDialog()
設定按鈕,只有連線按鈕可用
GetDlgItem(IDC_connectBTN)->EnableWindow(true);
GetDlgItem(IDC_Send)->EnableWindow(false);
GetDlgItem(IDC_search)->EnableWindow(false);
GetDlgItem(IDC_Login)->EnableWindow(false);
GetDlgItem(IDC_List)->EnableWindow(false);
GetDlgItem(IDC_Download)->EnableWindow(false);
GetDlgItem(IDC_logout)->EnableWindow(false);
GetDlgItem(IDC_BtnDisC)->EnableWindow(false);
2.2.2連線 & 斷開連線 C客戶端Dlg::OnBnClickedconnectbtn() &C客戶端Dlg::OnBnClickedBtndisc()
先初始化choice為0,表示準備接受伺服器金鑰。建立套接字並連線
int i = GetDlgItemInt(IDC_Port);
CString str;
GetDlgItemText(IDC_Addr, str);
m_pSocket = new MySocket;
m_pSocket->choice = 0;
choice = 0;
if (FALSE == m_pSocket->Create())
{
MessageBox(_T("套接字建立失敗"));
return;
}
if (FALSE == m_pSocket->Connect(str,i))
{
MessageBox(_T("伺服器連線失敗"));
return;
}
MessageBox("成功連線伺服器");
設定按鈕屬性。因為連線上了,所以可以上傳檔案和登陸了,也可以斷開連線。
GetDlgItem(IDC_Send)->EnableWindow(true);
GetDlgItem(IDC_search)->EnableWindow(true);
GetDlgItem(IDC_Login)->EnableWindow(true);
GetDlgItem(IDC_BtnDisC)->EnableWindow(true);
GetDlgItem(IDC_connectBTN)->EnableWindow(false);
初始化檔案目錄,我的檔案目錄不小心建在m_pSocket裡面的,但是顯示沒有問題。所以我也沒有改回來。邏輯沒有問題,就是和伺服器的設計有點不統一而已。因為還沒有登陸,檔案目錄不顯示。
tab.InsertItem(0, _T("檔案"));
m_pSocket->mPage.Create(IDD_contentDlg, GetDlgItem(1019));
//獲得IDC_TABTEST客戶區大小
CRect rs;
tab.GetClientRect(&rs);
//調整子對話方塊在父視窗中的位置
rs.top += 30;
rs.bottom -= 60;
rs.left += 1;
rs.right -= 2;
//設定子對話方塊尺寸並移動到指定位置
m_pSocket->mPage.MoveWindow(&rs);
//分別設定隱藏和顯示
m_pSocket->mPage.ShowWindow(false);
//設定預設的選項卡
tab.SetCurSel(0);
m_pSocket->mPage.m_FileList.SetExtendedStyle(LVS_EX_FULLROWSELECT);
m_pSocket->mPage.m_FileList.InsertColumn(0, _T("檔名"), LVCFMT_LEFT, 200);
m_pSocket->mPage.m_FileList.InsertColumn(1, _T("檔案大小"), LVCFMT_LEFT, 100);
斷開連線。就是關一下套接字。然後把按鈕還原成初始化的樣子
void C客戶端Dlg::OnBnClickedBtndisc()
{
// TODO: 在此新增控制元件通知處理程式程式碼
//MessageBox("斷開啦");
GetDlgItem(IDC_connectBTN)->EnableWindow(true);
GetDlgItem(IDC_Send)->EnableWindow(false);
GetDlgItem(IDC_search)->EnableWindow(false);
GetDlgItem(IDC_Login)->EnableWindow(false);
GetDlgItem(IDC_List)->EnableWindow(false);
GetDlgItem(IDC_Download)->EnableWindow(false);
GetDlgItem(IDC_logout)->EnableWindow(false);
GetDlgItem(IDC_BtnDisC)->EnableWindow(false);
closesocket(sClient);
WSACleanup();
}
2.2.3瀏覽檔案 &傳送檔案 C客戶端Dlg::OnBnClickedsearch() & C客戶端Dlg::OnBnClickedSend()
瀏覽主機裡的檔案,把路徑儲存到filePass (後來發現拼錯了,但是問題不大)裡面。
void C客戶端Dlg::OnBnClickedsearch()
{
// TODO: 在此新增控制元件通知處理程式程式碼
CFileDialog dlg(TRUE);
if (IDOK == dlg.DoModal())
{
filePass = dlg.GetPathName();
UpdateData(FALSE);
}
}
通過filePass找到檔案。先發送 傳送檔案的請求:choice==1 ,提醒伺服器要接受檔案了,然後傳送檔案資訊
WIN32_FIND_DATA wfd;
HANDLE hFinder = FindFirstFile(filePass, &wfd);
FindClose(hFinder);
choice = 1;
m_pSocket->Send(&choice, sizeof(choice));
m_pSocket->Send(&wfd, sizeof(wfd));
先開啟檔案,然後用位元組流的方式迴圈傳送檔案。
//傳送檔案內容
CFile file;
if (FALSE == file.Open(filePass, CFile::modeRead|CFile::typeBinary))
{
MessageBox("檔案開啟失敗");
return;
}
DWORD dwReadCount = 0;
char* buffer = new char[1024];
int n = 0;
while (dwReadCount < wfd.nFileSizeLow)
{
memset(buffer, 0, sizeof(buffer));
n=file.Read(buffer, 1023);
buffer[n] = '\0';
m_pSocket->Send(buffer, n);
dwReadCount += n;
}
delete[]buffer;
MessageBox(_T("釋出成功"));
2.2.4 登入 & 登出 C客戶端Dlg::OnBnClickedLogin() & C客戶端Dlg::OnBnClickedlogout()
登入。如果輸入的數值等於之前伺服器傳送的金鑰數字,則登陸成功。成功後顯示檔案目錄,登出、瀏覽檔案目錄、下載按鈕才可用,同時登入按鈕不可用。
void C客戶端Dlg::OnBnClickedLogin()
{
m_pLogin = new LoginDlg;
if (IDOK == m_pLogin->DoModal())
{
/*CString str;
str.Format(_T("% d"), KeyWord);
OutputDebugString(str);*/
if (m_pLogin->KeyWord == KeyWord)
{
ShowList();
GetDlgItem(IDC_List)->EnableWindow(true);
GetDlgItem(IDC_Download)->EnableWindow(true);
GetDlgItem(IDC_logout)->EnableWindow(true);
GetDlgItem(IDC_Login)->EnableWindow(false);
}
else
MessageBox("金鑰錯誤哦");
}
}
void C客戶端Dlg::ShowList()
{
//顯示目錄
m_pSocket->mPage.ShowWindow(true);
}
登出。就是隱藏檔案目錄,對按鈕再設定一下
void C客戶端Dlg::OnBnClickedlogout()
{
HideList();
GetDlgItem(IDC_List)->EnableWindow(false);
GetDlgItem(IDC_Download)->EnableWindow(false);
GetDlgItem(IDC_logout)->EnableWindow(false);
GetDlgItem(IDC_Login)->EnableWindow(true);
}
void C客戶端Dlg::HideList()
{
m_pSocket->mPage.ShowWindow(false);
}
2.2.5 瀏覽伺服器檔案 C客戶端Dlg::OnBnClickedList()
傳送一下瀏覽的請求,choice=2表示瀏覽伺服器的請求。然後套接字自動接收。會得到檔案目錄資訊。接收在後面寫。
void C客戶端Dlg::OnBnClickedList()
{
choice = 2;
m_pSocket->choice = 2;
m_pSocket->Send(&choice, sizeof(choice);
}
2.2.6 下載檔案 C客戶端Dlg::OnBnClickedDownload()
選中檔案,找到對應的檔案資訊。
POSITION ps;
int nIndex;
ps = m_pSocket->mPage.m_FileList.GetFirstSelectedItemPosition();
nIndex = m_pSocket->mPage.m_FileList.GetNextSelectedItem(ps);
//TODO:新增多選的操作。
if (nIndex == -1)
{
MessageBox("你還沒有選擇檔案哦");
return;
}
設定服務型別Choice==3,表示請求下載檔案。傳送請求,然後再發送檔案資訊。套接字自動接收
choice = 3;
m_pSocket->choice = 3;
m_pSocket->Send(&choice, sizeof(choice));
m_pSocket->Send(&(m_pSocket->deFile.at(nIndex)), sizeof(m_pSocket->deFile.at(nIndex)));
2.2.7接收檔案 MySocket::OnReceive(int nErrorCode)
通過Choice判斷接收內容。
choice==1,接收密碼。存到主對話方塊的KeyWord裡面,用於登入時的判斷
//得到金鑰數字
if (choice == 0)
{
C客戶端Dlg* pMainDlg=(C客戶端Dlg*)AfxGetMainWnd();
int kWord;
Receive(&pMainDlg->KeyWord, sizeof(pMainDlg->KeyWord));
CString str;
str.Format(_T("% d"), pMainDlg->KeyWord);
OutputDebugString(str);
}
choice==2.接收目錄資訊。先初始化(清空當前的目錄)。再得到檔案數量,迴圈獲得檔案資訊,資訊存到deFile裡面,再把資訊插入到檔案目錄裡
if (choice == 2)
{
//清空當前目錄檔案資訊
while (!deFile.empty())
{
deFile.pop_back();
}
mPage.m_FileList.DeleteAllItems();
//得到檔案總數
int sum;
Receive(&sum, sizeof(sum));
CString str;
WIN32_FIND_DATA wfd;
//迴圈得到檔案資訊
for (int i = 0; i < sum; i++)
{
//記錄檔案資訊到deFile
Receive(&wfd, sizeof(wfd), 0);
deFile.push_front(wfd);
//顯示檔案資訊到目錄中
mPage.m_FileList.InsertItem(0, wfd.cFileName);
str.Format(_T("%d"), wfd.nFileSizeLow);
mPage.m_FileList.SetItemText(0, 1, str);
}
OutputDebugString("收到所有啦啦");
}
Choice==3,接收檔案
if (choice == 3)
{
//迴圈接受檔案
WIN32_FIND_DATA wfd;
Receive(&wfd, sizeof(wfd), 0);
CString str;
CFile file;
if (FALSE == file.Open(wfd.cFileName, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary))
{
AfxMessageBox(_T("檔案開啟失敗"));
return;
}
DWORD dwReadCount = 0;
while (dwReadCount < wfd.nFileSizeLow)
{
char* buffer = new char[1024];
int n;
n = Receive(buffer, 1023);
buffer[n] = '\0';
dwReadCount += n;
OutputDebugString(_T("2"));
file.Write(buffer, n);
delete[] buffer;
}
AfxMessageBox(_T("收到啦"));
}
三、實驗結果及結果分析
3.1.監聽
伺服器監聽,監聽成功後,監聽按鈕不可用,金鑰數字不可再編輯。
客戶機和伺服器deBug輸出傳送/得到的金鑰
3.2.客戶端連線
客戶端請求連線。成功連線後,按鈕屬性發生變化
伺服器的客戶目錄顯示客戶端資訊
客戶機和伺服器deBug輸出傳送/得到的金鑰
第十章的那個程式碼設定了OnTimer,所以就是迴圈連線。我的沒有設定。有時候會連不上。就要重新連線。然後如果ip或者埠好出錯了,它要等好久,然後返回沒有連線上。
3.3瀏覽檔案併發送
傳送成功後顯示釋出成功,檔案目錄顯示。
伺服器在接受檔案時是創造檔案,如果有的話就直接接受。如果一個檔案發了兩次,目錄會顯示兩個,但是其實檔案只有一個。
3.4.登入
密碼不一致,顯示提示
登陸成功後可用其他的功能
3.5.瀏覽伺服器檔案
3.6.下載
沒有選取檔案顯示提示
因為伺服器對檔案不進行操作,所以沒有考慮檔案不存在的問題。所以如果檔案不存在的話,伺服器那邊顯示提示,客戶端這邊可能會報錯。
四、參考文獻
b站的視訊 https://www.bilibili.com/video/BV1Xt411K7fp?t=5903
還有一些函式和控制元件的用法都是隨查隨用的。很多很雜,不記得了。