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

还有一些函数和控件的用法都是随查随用的。很多很杂,不记得了。

这是我的代码
链接:https://pan.baidu.com/s/1hcC9CISOefLhbxhJE_i5_Q
提取码:xmrw

posted @ 2020-12-09 19:43  小夏的魔仙堡  阅读(145)  评论(0编辑  收藏  举报