中南大学计算机网络课程设计文件传输程序要点.docx
《中南大学计算机网络课程设计文件传输程序要点.docx》由会员分享,可在线阅读,更多相关《中南大学计算机网络课程设计文件传输程序要点.docx(15页珍藏版)》请在冰豆网上搜索。
中南大学计算机网络课程设计文件传输程序要点
第三章文件传输程序
3.1设计要求
包括客户端和服务器程序,应实现以下功能:
(1)客户端既能上传文件到服务器,也能从服务器下载文件;
(2)在客户端上可显示文件基本信息和传输状态信息,可浏览服务器上供下载的文件列表,选择某文件下载到本地某目录下;
(3)服务器端能接收客户端上传的文件,并保存在某一目录下;也能响应客户端的文件浏览与下载请求;
(4)增加其它附加创新功能。
程序应具有图形化界面,美观友好。
3.2设计思想
随着计算机网络的迅速发展,人们的生活越来越离不开网络,如今网络编程已成为计算机发展的热点,而在众多的网络通信中,又以TCP/IP协议最为流行。
本文讨论的Winsock控件,提供了访问TCP/IP网络的捷径,使用它可以不必了解TCP/IP的细节和调用WinsockAPI,只要设置好相应的属性和触发事件后的处理,就可以实现计算机之间的数据通信。
一、Winsock控件
Winsock即WindowsSockets规范的简称,是目前最流行的网络通信应用程序接口之一。
所谓Socket,通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄。
应用程序通常通过“套接字”向网络发出请求或者应答网络请求。
Socket是网络上运行的两个程序间双向通讯的一端,它既可以接受请求,也可以发送请求,利用它可以较为方便的编写网络上数据的传递。
Winsock控件工作在传输层上,在这一层上,目前主要流行的协议包括TCP和UDP两种:
TCP协议适用于那些对于数据的可靠性要求比较高的情况,目前大多数的网络应用层协议都是基于TCP协议的(例如常用的HTTP、FTP、SMTP、POP3等协议);UDP协议适用于对数据可靠性要求不高而对速度要求较高的情况,这里主要包括一些需要大流量的(例如Real公司的RTSP协议,腾讯公司的QQ协议等)。
二、Winsock控件通信的工作原理
Winsock控件是基于Socket规范创建的,所以其通信的实质是对Socket接口进行数据的读写操作。
如果两个应用程序需要通信,它们可以通过使用Socket类来建立套接字连接,可以将这个过程想象为一次电话呼叫过程:
呼叫者通过拨号与被呼叫者连接,当电话接通时,双方都可以自由通话了,只不过这里的呼叫者被称为“客户”,被呼叫者则称为“服务器”,而号码则为“IP地址+端口”,但在建立连接之前,必须由“客户”发出呼叫,且此时的“服务器”正在监听。
因此,基于TCP/IP协议的通信,需要分别建立客户端应用程序和服务器端应用程序。
其大致流程如图1所示:
图1Winsock工作原理
端口号被规定在0~65535范围内的某一个整数,其中0~1023被预先定义的服务器通信所占用(如telnet占用23,http占用端口80),所以最好使用1024~65535这些端口中的某一个,以免发生端口冲突。
三、基本方法
客户端要与服务器端进行通信,首先,必须知道服务器端的域名或IP地址(RemoteHost属性),就像要和某人打电话前,必须知道对方的电话号码;其次,还必须和服务器端约定相同的端口(RemotePort属性),用于数据的输入和输出;最后,调用Connect方法与服务器端建立连接。
服务器端应设置一个监听端口(LocalPort属性),端口应与客户端的端口相同,同时调用Listen方法时刻监听客户端的连接请求(ConnectionRequest事件);当接收到客户端的连接请求时,可调用ConnectionRequest事件的Accept方法,这样与客户端的连接就建立了。
客户端和服务器端成功建立连接后,任何一方都可以自由的发送数据(SendData方法)和接收数据(GetData方法),这些方法都在DataArrival事件中。
3.3编程实现过程
3.3.1开发环境
操作系统:
Windows7旗舰版
开发语言:
C++/MFC
编译环境:
MSVisualC++6.0
3.3.2程序界面设计
此程序根据功能需求,分别设计了客户端(图3-3-2-1)和服务器端(图3-3-2-2),实例如下:
图3-3-2-1
图3-3-2-2
3.3.3关键模块分析
1.文件选取
voidCTCPClientDlg:
:
OnSelect()
{
inti;
CFileMyFile;
CStringstrlen;
CFileDialogFileDlg(TRUE,NULL,NULL,
OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT|OFN_ALLOWMULTISELECT,
"AllFiles(*.*)|*.*||",NULL);
if(FileDlg.DoModal()==IDOK)
{
m_FilePath=FileDlg.GetPathName();
GetDlgItem(IDC_FLIENAME)->SetWindowText(m_FilePath);
i=m_FilePath.ReverseFind('\\');
m_FileName=m_FilePath.Mid(i+1);
//m_FileName=FileDlg.GetFileTitle();
MyFile.Open(m_FilePath,CFile:
:
modeRead);
m_FileLen=MyFile.GetLength();
strlen.Format("%ubytes",m_FileLen);
GetDlgItem(IDC_STATIC_LEN)->SetWindowText(strlen);
MyFile.Close();
}
//MyFile.Open(m_FilePath,CFile:
:
modeRead);
//UpdateData(FALSE);
}
2.文件发送
UINTSendTread(LPVOIDlpParam)
{
intiRxNum=0,iTxNum=0;//每次接受,发送,读取文件的字符数
UINTiTotal=0;//已发送文件长度
CFileMyFile;
CStringTempName,str;
CTCPClientDlg*m_pDlg=(CTCPClientDlg*)lpParam;
CProgressCtrl*m_ProgressCtrl1=&(m_pDlg->m_ProgressCtrl);
ClientSocket*pSocket=m_pDlg->m_pMySocket;
memset(sendbuf1,0,M);
//发送文件大小以及名字
sendbuf1[0]=m_FileLen/1000000000+48;
sendbuf1[1]=m_FileLen%1000000000/100000000+48;
sendbuf1[2]=m_FileLen%100000000/10000000+48;
sendbuf1[3]=m_FileLen%10000000/1000000+48;
sendbuf1[4]=m_FileLen%1000000/100000+48;
sendbuf1[5]=m_FileLen%100000/10000+48;
sendbuf1[6]=m_FileLen%10000/1000+48;
sendbuf1[7]=m_FileLen%1000/100+48;
sendbuf1[8]=m_FileLen%100/10+48;
sendbuf1[9]=m_FileLen%10+48;
a=strlen(m_FilePath);
sendbuf1[10]=a/1000+48;
sendbuf1[11]=a%1000/100+48;
sendbuf1[12]=a%100/10+48;
sendbuf1[13]=a%10+48;
if((N-10-4-a)>=m_FileLen)
times=1;
else
times=1+(m_FileLen-(N-10-4-a))/N+1;//表示最少两次,第一次和最后一次
//进度条初始化
m_ProgressCtrl1->SetRange(0,times-1);
m_ProgressCtrl1->SetPos(0);
m_ProgressCtrl1->SetStep
(1);
strcat(sendbuf1,(char*)m_FilePath.GetBuffer(m_FileLen));
pSocket->Send(sendbuf1,10+4+a,0);//m_ProgressCtrl;
//开始传输文件数据
str.Format("开始传送文件...");
m_pDlg->UpdateMGData(str);
MyFile.Open(m_FilePath,CFile:
:
modeRead);
if(times==1)
{memset(rx_buf,0,4);
memset(SendBuff,0,sizeof(SendBuff));
MyFile.Read(SendBuff,m_FileLen);
iTxNum=pSocket->Send(SendBuff,m_FileLen,0);
pSocket->Receive(rx_buf,4,0);
while(rx_buf[0]!
='K')
pSocket->Receive(rx_buf,4,0);
m_ProgressCtrl1->StepIt();
MyFile.Close();
str.Format("文件传送完毕,断开连接!
");
m_pDlg->UpdateMGData(str);
}
else
{
memset(SendBuff,0,sizeof(SendBuff));
full_times=times-2;
Times=times;
Times=Times-1;
MyFile.Read(SendBuff,N-10-4-a);
iTxNum=pSocket->Send(SendBuff,N-10-4-a,0);
while(Times--)
{
if(Times==0)
{
memset(rx_buf,0,4);
memset(SendBuff,0,sizeof(SendBuff));
MyFile.Read(SendBuff,m_FileLen-(N-10-4-a)-N*full_times);
pSocket->Receive(rx_buf,4,0);//如果收到K,则完成
while(rx_buf[0]!
='K')
pSocket->Receive(rx_buf,4,0);
iTxNum=pSocket->Send(SendBuff,m_FileLen-(N-10-4-a)-N*full_times,0);
m_ProgressCtrl1->StepIt();
str.Format("文件传送完毕,断开连接!
");
m_pDlg->UpdateMGData(str);
break;
}
if(Times>0)
{
memset(rx_buf,0,4);
memset(SendBuff,0,sizeof(SendBuff));
MyFile.Read(SendBuff,N);
pSocket->Receive(rx_buf,4,0);//如果收到K,则完成
while(rx_buf[0]!
='K')
pSocket->Receive(rx_buf,4,0);
iTxNum=pSocket->Send(SendBuff,N,0);
m_ProgressCtrl1->StepIt();
}
}//对应while
}
return0;
}
3.3.4结果演示与分析
图3-3-4-1
图3-3-4-2
图3-3-4-3
图3-3-4-4
图3-3-4-5
图3-3-4-6
图3-3-4-7
图3-3-4-8
图3-3-4-9
图3-3-4-10
图3-3-4-11
图1、图2分别为客户端和服务器端初始状态,图3客户端连接服务器端,图4服务器端侦听,客户端与服务器端连接成功,图5客户端选取文件,图6客户端发送文件,图7服务器端接受保存文件,图8客户端文件发送完毕,断开连接,图9服务器端接收成功,图10客户端断开与服务器端连接,图11服务器端停止侦听。