1. 程式人生 > 實用技巧 >TCP/IP文鍵傳輸系統

TCP/IP文鍵傳輸系統

一、設計原理

1.1伺服器

1.需求分析

(1)自定義金鑰數字,自定義埠,建立套接字字

(2)監聽,斷開監聽

(3)顯示接入的使用者

(4)收檔案

​ 自動接受並將檔案儲存到當前的文件中,並將檔名、大小、傳送者的IP存入目錄中

(5)發文件

​ 收到客戶機請求後,自動傳送檔案,無需人工操作

2.邏輯設計

​ 1.先監聽。收到使用者的連線後,將客戶的資訊存到客戶目錄中

​ 2.收到客戶的檔案傳送請求後,準備接收檔案。收到檔案後把檔案資訊存到檔案目錄中。檔案存到當前文件中

​ 3.收到客戶的目錄傳送請求後,傳送檔案數量,迴圈傳送檔案目錄中的檔案資訊。

​ 4.收到客戶的檔案下載請求後,準備接收檔案資訊。收到檔案資訊後,找到相應檔案傳送過去。

3.類和關鍵函式的設計

  1. Page1和Page2是用來儲存檔案資訊表和客戶資訊表的兩個對話方塊,在伺服器對話方塊的Tab Control控制元件裡。

  2. 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

還有一些函式和控制元件的用法都是隨查隨用的。很多很雜,不記得了。