通信软件设计三级项目文件传输软件.docx
《通信软件设计三级项目文件传输软件.docx》由会员分享,可在线阅读,更多相关《通信软件设计三级项目文件传输软件.docx(25页珍藏版)》请在冰豆网上搜索。
通信软件设计三级项目文件传输软件
XXX学院
通信软件设计三级项目设计说明书
(XXXX学年XX学期)
课程名称:
通信软件设计三级项目
题目:
文件传输软件
专业班级:
XXXXXXXXX
学生姓名:
XXXXXXX
学号:
XXXXXX
指导教师:
XXXXXXXXXXXXXXXXXX
设计周数:
XXX
设计成绩:
XXXX年XX月XX日
通信软件设计三级项目任务书
一、题目:
文件传输软件
二、班级:
XXXXXXXXXXX
三、小组成员:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
四、起止时间:
XXXXXXXXXXXXXXXXXXXXXXXXX
五、设计要求与思路:
要求软件能够方便地实现局域网中主机之间的文件传输。
为了可靠传送文件,建议使用TCP提供的服务器。
可以考虑采用C/S架构,可以采用Pull方式(客户端主动获取文件,服务器端被动地提供文件),也可以采用Push方式(客户端主动发送文件,服务器端被动地接收文件)。
也可以采用P2P架构(稍微复杂,但更好用),例如使用UDP方式在对等方之间传递文本消息以及用于发起文件传输的控制信息,实际进行文件传输时仍通过TCP连接进行。
基本设计思路是先建立TCP连接,连接成功后,发送文件的一方从文件流读取数据,写入网络流,接收方读取网络流,写入文件流,完成后断开TCP连接,释放相关的资源。
六、主要任务:
1、深入理解TCP的工作原理和服务的特性,掌握TCP套接字编程机制和方法;
2、理解C/S架构,理解Pull和Push两种文件传输模式;
3、深入分析文件发送方和接收方的程序运行流程,绘制程序流程图;
4、学习使用OpenFileDialog、SaveFileDialog、FileStream;
5、完成服务器端软件和客户端软件的开发和测试;
6、按照格式要求撰写设计报告。
学生(签字):
指导教师(签字):
系主任(签字):
院长(签字):
目录
1课程设计要求与任务1
1.1课程设计要求1
1.2课程设计任务1
2课程设计正文1
2.1设计项目分析1
2.1.1文件传输软件1
2.1.2TCP传输协议1
2.1.3Socket编程2
2.2课程项目设计3
2.3软件界面设计4
2.4软件代码实现4
2.5软件测试12
3设计总结或结论14
3.1设计结论14
3.2设计总结14
4参考文献15
1、课程设计要求与任务
1.1课程设计要求
要求设计一款文件传输的软件,能够方便地实现局域网中主机之间的文件传输。
而为了可靠传送文件,建议使用TCP提供的服务器。
可以考虑采用C/S架构,可以采用Pull方式(客户端主动获取文件,服务器端被动地提供文件),也可以采用Push方式(客户端主动发送文件,服务器端被动地接收文件)。
也可以采用P2P架构(稍微复杂,但更好用),例如使用UDP方式在对等方之间传递文本消息以及用于发起文件传输的控制信息,实际进行文件传输时仍通过TCP连接进行。
基本设计思路是先建立TCP连接,连接成功后,发送文件的一方从文件流读取数据,写入网络流,接收方读取网络流,写入文件流,完成后断开TCP连接,释放相关的资源。
1.2课程设计任务
1、深入理解TCP的工作原理和服务的特性,掌握TCP套接字编程机制和方法;
2、理解C/S架构,理解Pull和Push两种文件传输模式;
3、深入分析文件发送方和接收方的程序运行流程,绘制程序流程图;
4、学习使用OpenFileDialog、SaveFileDialog、FileStream;
5、完成服务器端软件和客户端软件的开发和测试;
6、按照格式要求撰写设计报告。
2、课程设计正文
2.1设计项目分析
2.1.1文件传输软件
很多情况下,人们的日常工作需要借助文件传输来完成。
但大多数文件传输功能都需要借助移动磁盘等硬件设备或Internet才能实现。
这就给一些用户造成了许多问题,如硬盘中毒,网络资源浪费、工作效率降低等。
而开发一个基于局域网的文件传输工具,在内部网络中实现文件交换,则可以大大方便局域网内主机的资源共享。
基于局域网的文件传输系统的设计选用VirtualStudio2005为开发工具,以TCP服务器模式通过建立Socket连接后实现局域网快速,准确,安全的点对点文件以及文件夹传输功能。
2.1.2TCP传输协议
针对于所要求设计的软件最终目的:
实现局域网中主机之间的文件传输这一功能,考虑到可靠的传送文件,我们选择使用TCP提供的服务器。
对于TCP传输协议及其工作原理,叙述如下:
TCP,传输控制协议(TransportControlProtocol),是一种面向连接的、可靠的传输层协议。
面向连接指其一次正常的TCP传输需要通过在TCP客户端和TCP服务端建立特定的虚电路连接来完成,该过程通常被称为“三次握手”。
可靠性可以通过很多种方法来提供保证,在这里我们关心的是数据序列和确认。
TCP通过数据分段(Segment)中的序列号保证所有传输的数据可以在远端按照正常的次序进行重组,而且通过确认保证数据传输的完整性,并提供拥塞控制机制,当网络拥塞时,源抑制其传输速率。
要通过TCP传输数据,必须在两端主机之间建立连接。
TCP连接建立过程如图2-1所示。
图2-1TCP连接建立过程
2.1.3Socket编程
Socket编程是建立在应用层TCP/IP协议之上的。
目前最流行的是客户机/服务器模式,在面向连接的Client/Server模型中,Server端的socket总是等待一个Client端的请求。
客户机/服务器模型的工作流程图如下图1所示:
图1客户机/服务器模型的工作流程
(1)服务器(接收方)程序特点:
1一般启动后就一直处于运行状态,以等待客户机进程的请求;
2使用的端口往往是熟知端口,便于客户机进程连接请求;
3一般拥有较多的系统资源,以便及时响应各个客户机进程的请求;
4可以并行处理多个客户机进程的请求,但数目是有一定的限制;
5在通信时一般处于被动的一方,不需要知道客户机的IP地址和端口信息。
(2)客户机(发送方)程序的特点:
①在需要服务器进程的服务时将向服务器进程请求服务,并建立通信连接,得到满足并完成处理后就终止通信连接;
②使用向系统申请的临时端口与服务器进程进行通信,通信完成后将释放该端口;
③拥有相对较少的系统资源;
④在通信时属于主动的一方,需要事先知道服务器的IP地址和端口信息
2.2课程项目设计
项目设计为客户机/服务器即当主机主动发起连接或者主动传输文件时,该主机为客户机,当处于监听状态,被连接时或者被动接收文件时,该主机为服务器。
执行一个线程的时,同步调用必须等待这段代码执行完返回结果后,调用方才能继续往下执行,并且同步调用又叫阻塞调用,他阻塞当前线程,然后执行调用,当调用完毕后在继续向下进行。
异步调用,调用方和被调方可以属于两个不同的线程,调用方启动被调方线程后,不等对方返回结果就继续执行后续代码,可以执行多个线程,并且可以避免阻塞,所以将在本程序中采用异步调用的方式启动线程。
程序流程图如图2-2所示。
图2-2程序流程图
2.3软件界面设计
此次文件传输软件界面设计如图2-3所示。
软件设计大致有三模块组成:
首先,两台主机IP模块,再者则是文件传输区,包括文件的选择、接收与发送;最后,作为完善,增加了聊天区域,完善了单纯文件传输功能这一弊端,使软件更实用化。
图2-3文件传输软件设计图
2.4软件代码实现
publicForm1()
{
InitializeComponent();
try
{
stringstr=Dns.GetHostName();
ip=Dns.GetHostAddresses(str);
//用来传输文本的本地网络端点
localendpoint=newIPEndPoint(ip[0],2000);
//用来传输文件的本地网络端点
filelocalendpoint=newIPEndPoint(ip[0],4000);
//实例化2个异步调用
callback=newAsyncCallback(startreceivesocket);
filecallback=newAsyncCallback(startfilereceivesocket);
//实例化文本和文件监听
tcplistener=newTcpListener(localendpoint);
filetcplistener=newTcpListener(filelocalendpoint);
this.lsb_Information.Items.Add("请选择监听或主动连接!
\r\n请确保对方处于监听状态才可发出连接申请!
\r\n否则需要重启这个这个程序!
\n");
}
catch(Exceptionex)
{
MessageBox.Show(ex.Message);
}
}
(1)启动线程,并在后台运行,在连接的时候打开
privatevoidopenth0()
{
th[0]=newThread(newThreadStart(th0process));
th[0].IsBackground=true;
if(th[0].IsAlive==false)
th[0].Start();
}
privatevoidopenth1()
{
th[1]=newThread(newThreadStart(th1process));
th[1].IsBackground=true;
if(th[1].IsAlive==false)
th[1].Start();
}
(2)听方,等待被连接那一方的监听程序
privatevoidth0process()
{
while(true)
{
try
{
if(receivesocket!
=null)
{
receivesocket.Blocking=true;
length=receivesocket.Receive(bytesreceived,bytesreceived.Length,0);
receivestring=System.Text.Encoding.GetEncoding("GB2312").GetString(bytesreceived,0,length);
this.Invoke(newshowmessage(showmessagetotextbox1),newobject[]{receivestring});
//这里是另外开的线程,直接用赋值语句是不行的
//不是主线程,所以不能对form上的控件直接进行访问
if(receivestring.Length>9)
if(receivestring.Substring(0,9)=="对方断开了当前连接!
")
{
this.Invoke(newresume(resumefunction));
closefunction();
}
if(receivestring.Length>12)
if(receivestring.Substring(0,12)=="对方取消了发送文件的请求!
")
{
this.Invoke(newresume(resumefilefunction));
closefilefunction();
}
if(receivestring=="对方拒绝了您发送文件的请求!
")
{
this.Invoke(newresume(resumefilefunction));
closefilefunction();
}
}
}
catch(Exceptionex)
{
MessageBox.Show(ex.Message);
}
}
}
(3)发送方的监听程序
privatevoidth1process()
{
while(true)
{
try
{
if(sendsocket!
=null)
{
sendsocket.Blocking=true;
length=sendsocket.Receive(bytesreceived,bytesreceived.Length,0);
receivestring=System.Text.Encoding.GetEncoding("GB2312").GetString(bytesreceived,0,length);
this.Invoke(newshowmessage(showmessagetotextbox1),newobject[]{receivestring});
if(receivestring.Length>9)
if(receivestring.Substring(0,9)=="对方断开了当前连接!
")
{
this.Invoke(newresume(resumefunction));
closefunction();
}
if(receivestring.Length>12)
if(receivestring.Substring(0,12)=="对方取消了发送文件的请求!
")
{
this.Invoke(newresume(resumefilefunction));
closefilefunction();
}
if(receivestring=="对方拒绝了您的连接请求!
")
closefunction();
if(receivestring=="对方拒绝了您传送文件的请求!
")
{
this.Invoke(newresume(resumefilefunction));
closefilefunction();
}
}
}
catch(Exceptionex)
{
MessageBox.Show(ex.Message);
}
}
}
(4)传文件时,主动发送方的传文件的程序
privatevoidtransferfile()
{
try
{
//这里每次发送之前都要受到对方发过来的信号是为了保证收发同步
if(filereceivesocket!
=null)
{
if(filereceivesocket.Connected)
{
//先发送文件名称,以便在保存文件时,有文件原始名称
filebytestosend=newbyte[filename.Length];
filebytestosend=Encoding.Unicode.GetBytes(filename);
filereceivesocket.Send(filebytestosend,filebytestosend.Length,0);
//随后发送文件长度,以便后面确定发送的次数filereceivesocket.Blocking=true;
length=filereceivesocket.Receive(filebytesreceived,filebytesreceived.Length,0);
startstring=Encoding.Unicode.GetString(filebytesreceived,0,length);
if(startstring=="下面是长度")
{
FileInfofiletosend=newFileInfo(filepath);
sendfilelength=filetosend.Length;
filebytestosend=newbyte[sendfilelength.ToString().Length];
filebytestosend=Encoding.Unicode.GetBytes(sendfilelength.ToString());
filereceivesocket.Send(filebytestosend,filebytestosend.Length,0);
}
//最后发送文件本身的内容
filereceivesocket.Blocking=true;
length=filereceivesocket.Receive(filebytesreceived,filebytesreceived.Length,0);
startstring=Encoding.Unicode.GetString(filebytesreceived,0,length);
if(startstring=="开始")
{
FileStreamfs=newFileStream(filename,FileMode.Open,FileAccess.Read);
filebytestosend=newbyte[32768];
temp=0;
//这里每次都要清零否则会留下上次传送文件长度的痕迹
this.Invoke(newMethodInvoker(this.timer1.Start));
while(temp{
sendlengthtemp=fs.Read(filebytestosend,0,filebytestosend.Length);
filereceivesocket.Send(filebytestosend,sendlengthtemp,0);
temp+=sendlengthtemp;
System.Threading.Thread.Sleep(200);
}
fs.Close();
}
else
{
temp=sendfilelength+1;
}
this.Invoke(newshowmessage(showmessagetotextbox1),newobject[]{"文件已传输完毕"});
this.Invoke(newresume(resumefilefunction));
MessageBox.Show("文件已传输完毕");
closefilefunction();
}
}
}
catch(Exceptionex)
{
MessageBox.Show(ex.Message);
}
}
(5)接收文件时,接收方的程序
privatevoidreceivefile()
{
try
{
if(filesendsocket!
=null)
{
if(filesendsocket.Connected)
{
filesendsocket.Blocking=true;
length=filesendsocket.Receive(filebytesreceived,filebytesreceived.Length,0);
filereceivestring=Encoding.Unicode.GetString(filebytesreceived,0,length);
//接受从对方传过来的文件的原有文件名
saveFileDialog1.Title="另存为";
saveFileDialog1.FileName=filereceivestring;
//显示另存为对话框
this.Invoke(newshow(showdialog));
filestringtosend="下面是长度";
//随意发送一个信号,为了确保收发同步,以免这边还没接收完,那边已全发送完了sendfilefunction(filestringtosend);
length=filesendsocket.Receive(filebytesreceived,filebytesreceived.Length,0);
filereceivestring=Encoding.Unicode.GetString(filebytesreceived,0,length);
//获取文件的长度
receivedfilelength=long.Parse(filereceivestring);
//将数字的字符串表示形式转换为它的等效64位有符号整数filestringtosend="开始";
//这也是随意发送的一个记号,为收发同步
sendfilefunction(filestringtosend);
FileStreamfs=newFileStream(savedfilepath,FileMode.Create,FileAccess.Write);
temp2=0;
//这里每次temp2都要清零,否则会留下上次收到数据的长度的痕迹this.Invoke(newMethodInvoker(this.timer2.Start));
//下面是接收文件的具体内容
while(temp2{
receivedlengthtemp=filesendsocket.Receive(filebytesreceived,filebytesreceived.Length,0);
temp2+=receivedlengthtemp;
fs.Write(filebytesreceived,0,receivedlengthtemp);
System.Threading.Thread.Sleep(200);
}
fs.Close();
this.Invoke(newshowmessage(showmessagetotextbox1),newobject[]{"文件已传输完毕"});
this.Invoke(newresume(resumefilefunction));
MessageBox.Show("文件已传输完毕");
closefilefunction();
}
}
}
catch(Exceptionex)
{
MessageBox.Show(ex.Message);
}
}
//接收文件方向发方发送消息,以便同步
privatevoidsendfilefunction(stringstr)
{
filebytestosend=newbyte[str.Length];
filebytestosend=Encoding.Unicode.GetBytes(str);
filesendsocket.Send(filebytestosend,filebytestosend.Length,0);
}
(6)监听线程和关闭线程
这要运行到beginacceptsocket函数时,就会开辟这个线程,一直等到有对方发出连接请求来,否则这个线程一直在后台运行,所以有时监听然后复位后,这个监听线程