具体代码已上传csdn下载http://download.csdn.net/detail/u014277388/9569056
计算机网络
实验报告
实验名称: |
TCP/IP协议的应用 |
|||
姓名: |
中年英雄王叔叔 |
学号: |
||
专业: |
信息管理与信息系统 |
班级: |
||
指导教师: |
陈君 |
|||
一、实验目的
了解和掌握基于socket的网络编程技术,开发基于socket的网络应用。
二、实验内容与实验步骤
【实验内容】
了解应用编程接口API,掌握基于socket的网络编程的原理,开发利用socket的TCP文件传输应用程序。该应用需要具备的功能以及实现的要点描述如下:
1.该程序应该包括服务器应用程序以及客户应用程序。
2.用户需要身份验证。即对于客户端来说,无论是上传文件,还是下载文件,首先需要做的事情是登陆服务器,得到服务器的验证。 若验证成功,即可与服务器之间开始传输文件。若验证失败,服务器则返回错误信息。错误信息包括,用户名错误,密码错误等。
3.理解文件传输的原理。所谓文件传输,对于发送端来说,实质是将数据读入发送缓存再将其发送。对于接收端来说,实质是从接收缓存里读取数据并将其写入到指定的位置。
4.请注意理解文件传输的含义。文件,指的是一切可以传输的信息,包括文本文件、图片文件、视频文件等。传输,指的是服务器和客户端都可以成为文件的发送者。从客户端的角度来说,客户端向服务器传送文件称为上传,服务器向客户端传送文件称为下载。
【实验步骤】
1. 阅读老师提供的示例程序,了解和掌握socket网络编程的原理
2. 根据实验要求,开发基于TCP的文件传输服务器端程序
3. 开发基于TCP的文件传输客户端程序
4. 编译程序、调试程序、运行程序
5. 写实验报告,>800字,提交设计程序
三、实验环境
硬件环境:
处理器:Intel(R) Core(TM) i5-3230M CPU @ 2.60GHz
安装内存:(RAM):2GB
软件环境:
操作系统:Windows7
开发工具:Eclipse(JRE1.7版本)
四、实验过程与分析
1.知识准备
通过阅读老师提供的实例程序以及实验要求,我大概对要做的程序心里有个预期,因为对Java的理解相较其他比较深,所以决定要选择用Java进行编程。然后Java开发工具中在Java.net包中是含有Socket和ServerSocket分别表示双向连接的客户端和服务器端。然后参照一个Socket简单通信实例(http://blog.csdn.net/gxy3509394/article/details/7899923)了解了大概怎么进行使用这两个类,(该程序并不含文件传输功能)并试着加入GUI界面,运行结果如下图:
接着在网上查找资料(http://www.cnblogs.com/mengdd/archive/2013/03/10/2952616.html、http://www.cnblogs.com/rond/p/3565113.html、基于Java的通信软件设计)等文献或者博客理解这两个类。
该图显示的为在Java封装socket情况下的通信,没有体现bind()方法,当然利用Java也可以进行显式的使用,比如可以像下面这样,当然依然设为127.0.0.1,因为服务器为本地服务器,此外对于该ip地址系统不会将数据放入数据链路层,而是直接在客户端和服务器直接传递。
ss =new ServerSocket();
Stringip="127.0.0.1";
intport=7888;
InetSocketAddressaddr=new InetSocketAddress(ip,port);
ss.bind(addr);
ss.accept();
此外,关于GUI图形化界面方面的知识,也是看些网上的教程慢慢上手的。
2.程序概述
在本次实验过程中,我在Java项目*新建了四个包,分别是:Chat包(聊天功能,主要用来学习Java中的Socket类)、Server包(包含服务器的程序)、Client包(包含客户端各种功能的程序以及GUI程序)、FileTransfer包(实现客户端文件传输GUI界面以及功能)。由于Chat包与本次实验关联不大,故不再进行介绍。
1.服务器端 (Server包)
类名(class) |
方法(method) |
作用 |
Server |
Server() |
构造函数,建立套接字 |
log(BufferedReader br, PrintWriter pw) |
登录函数,验证客户端传来的帐号密码是否正确 |
|
register(BufferedReader br, PrintWriter pw) |
注册函数,将客户端传来的帐号密码写入"用户资料"文件 |
|
changepassword(BufferedReader br, PrintWriter pw) |
修改密码函数,允许用户修改密码,并将其保存至用户资料 |
|
upload(BufferedReader br, PrintWriter pw) |
允许用户上传各种文件类型到文件数据库中 |
|
showdatabase(BufferedReader br, PrintWriter pw) |
让用户可以选择文件数据库中的文件进行下载 |
|
download(BufferedReader br, PrintWriter pw) |
将用户在文件数据库选择的文件传到客户端 |
|
main() |
主函数,建立一个服务器对象 |
2.客户端(Client包和FileTransfer包)
Client包
类名(class) |
方法(method) |
作用 |
Client |
createConnection(int port) |
向服务器发出请求,建立套接字连接 |
Client(int port) |
构造函数调用createConnection方法 |
|
main() |
主函数,建立一个客户端对象 |
|
MainLog |
MainLog(Client client) |
实例化MainLog界面以及Client对象 |
actionPerformed(ActionEvent e) |
监听鼠标的动作,并调用相关方法 |
|
main() |
主函数,建立一个客户端对象 |
|
Log |
Log(Client client) |
构造函数,实例化Log界面以及Client对象 |
actionPerformed(ActionEvent e) |
监听鼠标的动作,并向服务器传递登录信号,完成登录功能 |
|
Register |
Register (Client client) |
构造函数,实例化Register界面以及Client对象 |
actionPerformed(ActionEvent e) |
监听鼠标的动作并向服务器传递注册信号,将账户信息发送给服务器 |
|
ChangePassword |
ChangePassword (Client client) |
构造函数,实例化ChangePassword界面以及Client对象 |
actionPerformed(ActionEvent e) |
监听鼠标的动作并向服务器传递修改密码信号,将新的账户信息发送给服务器 |
FileTransfer包
类名(class) |
方法(method) |
作用 |
FileTransfer |
FileTransfer(BufferedReader br, PrintWriter pw) |
构造函数,实例化FileTransfer界面以及Client对象 |
actionPerformed(ActionEvent e) |
监听鼠标的动作,并调用相关方法 |
|
Upload |
Upload(BufferedReader br, PrintWriter pw) |
构造函数实例化Upload界面 |
UploadListener |
UploadListener(JLabel filenamelabel, JProgressBar progressbar,BufferedReader br, PrintWriter pw) |
构造函数,实例化上传相关参数 |
actionPerformed(ActionEvent e) |
监听鼠标的动作,并实现客户端请求进行文件上传功能 |
|
Download |
Download(BufferedReader br, PrintWriter pw) |
构造函数,实例化Download界面 |
DownloadListener |
DownloadListener (JLabel filenamelabel, JProgressBar progressbar,BufferedReader br, PrintWriter pw) |
构造函数,实例化下载相关参数 |
actionPerformed(ActionEvent e) |
监听鼠标的动作,并实现客户端请求进行文件下载功能 |
3.程序运行情况
1.客户端与服务器建立连接
Server类的构建:创建ServerSocket对象服务器端口号(本次实验登记端口号为:8888,文件传输端口号为:6666);创建Socket利用accept()方法来监听接收客户发来的连接请求;创建进行信息传输的IO流;
Client类的构建:利用主机IP以及端口号创建客户端的Socket,并发出连接请求;
Server与Client建立连接:先启动服务器,然后打开客户端,可以在服务器端看到客户的运行情况
2.客户端运行展示
客户端首页:
包含登陆、注册、修改密码三个按钮,同时为三个按钮添加监听器,触发之后分别弹出相应界面。
登录界面:
在账号输入框中输入账号,在密码输入框中输入密码,点击登陆,即将信息传输至服务器端进行验证。根据服务器中用户资料文件中的信息进行比较,若密码和账号均一致,即登录成功,可能出现密码错误或账号不存在的情况。
注册界面:
在账号输入框中输入账号,在密码输入框中输入密码,在确认密码框中再次输入密码,点击确认,在客户端首先会进行密码与确认密码的匹配,若两者一致,且用户资料中无该用户,则传入服务器进行写入用户资料中,可能出现提示两次密码不一致或者该用户名已注册等情况。
修改密码界面:
在账号输入框中输入账号,在原密码输入框中输入旧密码,在新密码框中输入想要设定的新密码,在确认密码框里再次输入新密码,点击确认,在客户端首先会进行新密码与确认密码的匹配,若两者一致,且用户资料中已有该用户,则传入服务器改写用户资料,可能出现提示两次密码不一致、该用户名未注册等情况以及原始密码不对的情况。
文件上传与下载界面:
包含上传与下载两个按钮,同时为每个按钮添加监听器,触发之后分别弹出相应上传或下载的界面。
文件上传界面:
选择对应的文件上传按钮,弹出文件选择功能;选中所要上传的文件,文件即被上传至服务器的文件数据库中,进度条达100%,即上传成功,并弹出"文件上传成功"的提示。
文件下载界面:
文件下载界面展示了服务器端所有可供下载的文件;选择对应的文件点击后方的下载按钮,弹出文件下载位置选择框;选中所要下载文件的位置,当进度条到达100%时,文件即被下载至客户端下载完成,同时弹出"文件下载成功"的提示。
3.服务器运行展示
对于刚才用户的所有操作,服务器都会对相应操作进行监控显示
用户帐号信息被储存在一个txt文件中,上传文件的目的地址和下载文件的数据库均在文件夹"文件数据库中"。
五、实验结果总结与思考
本次实验刚刚接触时没有头绪,但是实验时间确实很充足,所以很多问题都慢慢理解明白了。总体感觉实验还是有一定难度,但是由于操作系统原理那门课也有一些相关方面的知识,所以对于这次的文件运输程序,自己在编的过程越来越懂、也越来越有成就感。
1.对于端口号的理解。开始并不是很懂TCP连接,于是对于出现Socket类和ServerSocket类全部使用toString()方法,观察并总结规律,再结合书上的讲解,我理解了对于服务器端,其用ServerSocket类绑定的端口即为本地端口,而远程端口打印的每次都不一样是因为客户端使用的端口号,是客户进程暂时使用的端口号,此次通信结束即释放该端口;而对于客户端,Socket(ip,port)即产生一个与之对应的本地端口,而其中的port即成为其远程端口。
2.服务器对于不同的进程最好使用不同的端口号,本次实验即采用了两个端口号,一个是登记端口号8888,文件传输端口号为6666,这样实现了可以在进行文件内容信息传输的同时也能传输登记控制信息的传输,避免了某次文件传输过后是登记控制信息也无法传递的情况。
3.特殊IP地址的使用。服务器端口ss绑定的IP地址为0.0.0.0,代表本主机的所有IP地址。而客户端准备绑定的地址为127.0.0.1或Localhost,两者其实本质上都是代表本机地址或者说本地服务器,他们的关系是通过操作系统中的hosts文件,将Localhost解析为127.0.0.1。他们的关系是通过操作系统中的hosts文件,将Localhost解析为127.0.0.1。Localhost好处在于不占用网卡资源。
4.本次实验是使用GUI界面最为复杂的一次,还包括了监听器的使用都是第一次,对Java中窗口的理解、三层面板的理解以及窗体布局都有了更加深刻的理解。
5.一开始对于整个实验也有一部分是基于FTP文件传输协议,比如客户端应该实现用户界面,而在服务器端只需要能够监控用户使用信息即可;又如FTP专门区别数据传送进程和控制进程,在本次实验一样受用.
6.对于要实现的不同功能,客户端都是专门的一个类去实现,使程序可读性变强。并且在服务器端采用while(true)无限循环的结构,使服务器监听打开后一直持续监听,采用if-else结构对于客户端传来的请求调用相应的方法实现。
7.关于上传和下载界面的进度条,我在网上先找到一个类似的Java的Socket的传输文件的程序,模仿其编了个类似的进度条,通过上网查找资料,我懂得了因为所编写的程序本身为单线程运行,而GUI界面发生改变需要另外的单线程,所以在代码中可以看到是新建了一个线程实现文件的上传与下载。
8.本次实验的核心是关于Socket通信的原理,通过学习我们已经知道TCP协议是面向字节流的,而Java是利用getOutputStream()和getInputStream()得以实现的;而且关于IP地址的设置,若设置为远程IP,这能实现远程的进程通信,这也是很多大型软件的基础;总之我对运输层以及Socket等方面的知识都有了更深的理解。
核心代码:
服务器端
package Server;
//Java中 socket通信已经被封装好了主要使用两个类ServerSocket和Socket
import java.net.ServerSocket;
import java.net.Socket;
import java.io.*;
import javax.swing.JOptionPane;
/*
*服务器具体
*/
publicclass Server{
//设定服务器端口号为8888
int port=8888;
public Server()throws Exception {
JOptionPane.showMessageDialog(null,"服务器开始启动","服务器端",
JOptionPane.INFORMATION_MESSAGE);
//套接字socket
Socket s=null;
//服务器段serversocket
ServerSocket ss=new ServerSocket(port);
System.out.println("监听端口:"+ ss.toString());
// socket监听,即为等待请求,此方法会一直阻塞,直到获得请求才往下走,返回类型为Socket类
s= ss.accept();
System.out.println("登记端口:"+ s.toString());
//用于接收客户端发来的请求
BufferedReader br=new BufferedReader(new InputStreamReader(
new DataInputStream(s.getInputStream())));
//用于发送返回信息
PrintWriter pw=new PrintWriter(new DataOutputStream(
s.getOutputStream()));
//服务器持续工作
while(true){
//接受客户端,看是哪种请求,并调用相应的函数
char clientchar=(char) br.read();
try{
if(clientchar=='L'){
System.out.println("用户正在进行登录");
log(br, pw);
}elseif(clientchar=='R'){
System.out.println("用户正在进行注册");
register(br, pw);
}elseif(clientchar=='C'){
System.out.println("用户正在修改密码");
changepassword(br, pw);
}elseif(clientchar=='U'){
System.out.println("用户正在进行上传操作");
upload(br, pw);
}elseif(clientchar=='D'){
System.out.println("用户正在进行下载操作");
download(br, pw);
}elseif(clientchar=='S'){
System.out.println("用户正在浏览数据库");
showdatabase(br, pw);
}
}catch(Exception e){
//打印异常
e.printStackTrace();
if(s!=null){
try{
ss.close();
ss=null;
}catch(Exception ex){
ex.printStackTrace();
}
System.out.println("远程连接异常,关闭连接");
}
}
}
}
/*
*登陆
*/
publicvoid log(BufferedReader br, PrintWriter pw)throws Exception{
//客户端账号
String account= br.readLine();
//密码文件相对路径
String userdatapath="用户资料.txt";
//从密码文件读取内容的IO流
BufferedReader userdata=new BufferedReader(new FileReader(
userdatapath));
//从文件中读取的每行内容
String strline;
//向客户端发送的账号是否存在结果,预置为no
String accountresult="no";
//循环读取文件内容,直至为空
while((strline= userdata.readLine())!=null){
//将分拣内容以逗号切分,第一个字符串为账号,第二个字符串为密码
String[] str= strline.split(",");
//已有账号和传来的账号匹配
if(str[0].equals(account)){
accountresult="yes";
break;
}
}
//回传账号是否存在的结果
pw.println(accountresult);
pw.flush();
//关闭读取密码文件的流
userdata.close();
//重新开启读取密码文件的流
userdata=new BufferedReader(new FileReader(userdatapath));
//如果账户存在
if(accountresult.equals("yes")){
//客户端密码
String password= br.readLine();
//密码与账号是否匹配的结果,预置为1
String passwordresult="no";
while((strline= userdata.readLine())!=null){
//将分拣内容以逗号切分,第一个字符串为账号,第二个字符串为密码
String[] str= strline.split(",");
//已有账号和传来的账号匹配
if(str[0].equals(account)){
//同时对应的密码也匹配
if(str[1].equals(password)){
//检验结果置为yes,代表密码和账号匹配
passwordresult="yes";
break;
}
}
}
//关闭读取密码文件的IO流
userdata.close();
//将检验结果发给客户端
pw.println(passwordresult);
pw.flush();
}
}
/*
*注册
*/
publicvoid register(BufferedReader br, PrintWriter pw)throws Exception{
//客户端账号
String account= br.readLine();
//密码文件相对路径
String userdatapath="用户资料.txt";
//读取密码文件的IO流
BufferedReader userdata=new BufferedReader(new FileReader(
userdatapath));
//密码文件的每行内容
String strline;
//账号是否存在的检验结果,预置为yes
String exist="yes";
// exist是否改动过的标志位,预置为0
int flag=0;
//循环检验账号是否已存在,逼迫客户端不断输入新的账号,直至传来的账号不存在
while(exist.equals("yes")){
//循环读取文件内容,直至为空
while((strline= userdata.readLine())!=null){
//将每行内容按逗号切分,第一字符串为账号,第二字符串为密码
String[] str= strline.split(",");
//已有账号和传来的账号匹配
if(str[0].equals(account)){
//标志位置为1,跳出
flag=1;
break;
}
}
//标志位为0,证明账户不存在
if(flag==0){
exist="no";
}
//向客户端发送检验结果
pw.println(exist);
pw.flush();
//如果账号存在,继续从客户端读取新的账号
if(exist.equals("yes")){
account= br.readLine();
}
}
//关闭从文件读取的流
userdata.close();
//实例化向密码文件输入的IO流,文件末尾追加写入
FileWriter fw=new FileWriter(userdatapath,true);
//接受客户端密码
String password= br.readLine();
//向密码文件写入账号和密码
fw.write(account+","+ password+"\n");
//关闭写入流
fw.close();
}
/*
*更改密码
*/
@SuppressWarnings("resource")
publicvoid changepassword(BufferedReader br, PrintWriter pw)
throws Exception{
//客户端账号
String account= br.readLine();
//从客户端传来的旧密码
String oldpassword= br.readLine();
//密码文件相对路径
String userdatapath="用户资料.txt";
//读取密码文件的IO流
BufferedReader userdata=new BufferedReader(new FileReader(
userdatapath));
//密码文件的每行内容
String strline;
//账号密码是否匹配的检验结果,预置为no,即不存在
String exist="no";
// exist是否需要改动的标志位,预置为0,
int flag=0;
//循环检验账号、密码是否和密码文件中的匹配,逼迫客户端不断输入账号、密码,直至传来的账号、密码和密码文件中的匹配
while(exist.equals("no")){
//循环读取文件内容,直至为空
while((strline= userdata.readLine())!=null){
//账号、密码和密码文件中的匹配
if(strline.equals(account+","+ oldpassword)){
flag=1;
break;
}
}
// flag=1,证明exist需要改动,变为yes
if(flag==1){
exist="yes";
}
//将检验结果发送给客户端
pw.println(exist);
pw.flush();
//账号、密码和密码文件中的不匹配,继续从客户端读入新的账号、密码
if(exist.equals("no")){
account= br.readLine();
oldpassword= br.readLine();
}
}
//新密码
String newpassword= br.readLine();
//从密码文件读取内容的输入流
FileReader fr=new FileReader(new File(userdatapath));
//用来接受从文件中读取的内容的数组
char[] data=newchar[1024];
//每次读取内容的数量
int rn=0;
//构建StringBuilder类
StringBuilder sb=new StringBuilder();
//读取内容不为空
while((rn= fr.read(data))>0){
//将数组中的内容形成字符串
String str= String.valueOf(data,0, rn);
//将字符处内容追加到sb尾部
sb.append(str);
}
//关闭fr
fr.close();
//将sb中的账号+旧密码的部分换为账号+新密码,并转为字符串
String str= sb.toString().replace(account+","+ oldpassword,
account+","+ newpassword);
//写入密码文件的输出流
FileWriter fw=new FileWriter(userdatapath);
//将str写入文件
fw.write(str);
//关闭fw
fw.close();
}
/*
*客户端上传文件
*/
publicvoid upload(BufferedReader br, PrintWriter pw){
try{
//构建传输文件的socket
ServerSocket serversocket=new ServerSocket(6666);
Socket s= serversocket.accept();
System.out.println("上传端口:"+ s.toString());
//用于写入新文件的IO流
DataInputStream dis=new DataInputStream(s.getInputStream());
//上传文件路径
String path="文件数据库/"+ dis.readUTF();
//定义长度为8192的缓冲字节,
int bufferSize=8192;
byte[] buf=newbyte[bufferSize];
//写入文件内容的IO流
DataOutputStream fileOut=new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(
"G:/java程序/计算机网络/"+ path)));
while(true){
int read=0;
if(dis!=null){
// dis读入缓冲数组buf,得到长度read
read= dis.read(buf);
}
// read=-1时,证明接受完成,文件读空
if(read==-1){
break;
}
//将buf中读到的内容写入服务器端新文件
fileOut.write(buf,0, read);
}
//关闭IO流以及文件传输socket
fileOut.close();
dis.close();
s.close();
serversocket.close();
}catch(Exception e){
e.printStackTrace();
}
}
/*
*客户端下载文件
*/
publicvoid download(BufferedReader br, PrintWriter pw){
try{
//目标文件路径
String filePath="文件数据库/"+ br.readLine();
//实例化文件
File file=new File(filePath);
//读取文件的输入流
DataInputStream fis=new DataInputStream(new BufferedInputStream(
new FileInputStream(file)));
//构建传输文件的socket
ServerSocket serversocket=new ServerSocket(6666);
Socket s= serversocket.accept();
System.out.println("下载端口:"+ s.toString());
客户端传输文件内容的输出流
DataOutputStream dos=new DataOutputStream(s.getOutputStream());
//构建一个缓冲数组,长度为8192,类型为byte
int bufferSize=8192;
byte[] buf=newbyte[bufferSize];
//向客户端传输文件长度
dos.writeLong((long) file.length());
//循环从文件读取内容到buf,直至读完
while(true){
//每次读取内容长度
int read=0;
//读取流不为空,即有长度
if(fis!=null){
read= fis.read(buf);
}
// read=-1证明文件读空,可以结束循环
if(read==-1){
break;
}
//将buf中读取的内容写入dos
dos.write(buf,0, read);
}
//将dos中内容发送到客户端
dos.flush();
//关闭IO流以及文件传输socket
fis.close();
s.close();
serversocket.close();
}catch(Exception e){
e.printStackTrace();
}
}
/*
*向客户端展示可下载文件
*/
publicvoid showdatabase(BufferedReader br, PrintWriter pw){
//父结点文件夹路径
String parentPath="文件数据库";
//实例化父节点文件夹
File parentFile=new File(parentPath);
//将文件夹中文件存到数组list中
File list[]= parentFile.listFiles();
//将文件的总数量传给客户端
pw.println(list.length);
pw.flush();
//读取所有文件
for(int i =0; i< list.length; i++){
//如果是文件
if(list[i].isFile()){
//将文件名发送到客户端
pw.println(list[i].getName());
pw.flush();
}
}
}
//程序主函数,创建并运行服务器对象
publicstaticvoid main(String[] args)throws Exception {
new Server();
}
}
客户端
Client包:
package Client;
import java.net.Socket;
/*
*客户端连接
*/
publicclass Client{
//套接字先置为空,实例化时进行具体赋值
public Socket socket=null;
//网络号为127,主机号不全0全1的IP地址专门作为本地软件环回测试使用
private String ip="127.0.0.1";
//创建连接的方法
publicvoid createConnection(int port){
try{
//实例化socket
socket=new Socket(ip, port);
System.out.println("已连接服务器,登记端口:"+socket.toString());
}catch(Exception ex){
ex.printStackTrace();
//无法连接时,试图关闭原有Socket
if(socket!=null){
try{
socket.close();
socket=null;
}catch(Exception ex1){
ex1.printStackTrace();
}
System.out.println("连接异常,关闭连接");
}
}
}
public Client(int port){
//调用创建连接的函数
createConnection(port);
}
//客户端主程序
publicstaticvoid main(String[] args)throws Exception {
Client client=new Client(8888);
new MainLog(client);
}
}
package Client;
import java.awt.event.*;
import javax.swing.*;
import java.awt.*;
/*
*主界面
*实现ActionListener监听器
*/
publicclass MainLogimplements ActionListener{
//界面
private JFrame surface;
//登录按钮
private JButton logbutton;
//注册按钮
private JButton registerbutton;
//更改密码按钮
private JButton changepasswordbutton;
//连接配置
Client client;
public MainLog(Client client){
//实例化client以及上述各项
this.client= client;
surface=new JFrame("主页");
registerbutton=new JButton("注册");
registerbutton.setFont(new Font("黑体", Font.PLAIN,17));
logbutton=new JButton("登陆");
logbutton.setFont(new Font("黑体", Font.PLAIN,17));
changepasswordbutton=new JButton("修改密码");
changepasswordbutton.setFont(new Font("黑体", Font.PLAIN,17));
//界面布局及添加相应按钮、设置大小、位置以及可见
surface.setLayout(new GridLayout(3,1,6,0));
surface.add(logbutton);
surface.add(registerbutton);
surface.add(changepasswordbutton);
surface.setSize(300,200);
surface.setLocationRelativeTo(null);
surface.setVisible(true);
//为上传、下载、更改密码分别添加监听器
logbutton.addActionListener(this);
registerbutton.addActionListener(this);
changepasswordbutton.addActionListener(this);
}
/*
*监听器方法 (non-Javadoc)
*
* @see
* java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
publicvoid actionPerformed(ActionEvent e){
//触发登陆按钮,新建登陆界面,原主界面关闭
if(e.getSource()== logbutton){
new Log(client);
surface.dispose();
}
//触发注册按钮,新建注册界面,原主界面关闭
elseif(e.getSource()== registerbutton){
new Register(client);
surface.dispose();
}
//触发更改密码按钮,新建更改密码界面,原主界面关闭
elseif(e.getSource()== changepasswordbutton){
new ChangePassword(client);
surface.dispose();
}
}
publicstaticvoid main(String[] args)throws Exception {
Client client=new Client(8888);
new MainLog(client);
}
}
package Client;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import FileTransfer.FileTransfer;
//登录界面的实现
publicclass Logimplements ActionListener{
//界面
private JFrame frame;
//两个面板,分别是用户名和密码面板
private JPanel accountpanel;
private JPanel passwordpanel;
//用户名标签
private JLabel accountlabel;
//用户密码标签
private JLabel passwordlabel;
//用户名输入框
private JTextField accountcount;
//密码输入框
private JPasswordField passwordcount;
//登陆按钮
private JButton logbutton;
//后退按钮
private JButton backbutton;
//客户是其中的一个数据域
Client client;
public Log(Client client){
//实例化以上各元素
this.client= client;
frame=new JFrame("登陆");
accountlabel=new JLabel("账号:");
accountlabel.setFont(new Font("黑体", Font.PLAIN,16));
passwordlabel=new JLabel("密码:");
passwordlabel.setFont(new Font("黑体", Font.PLAIN,16));
accountcount=new JTextField();
passwordcount=new JPasswordField();
logbutton=new JButton("登陆");
logbutton.setFont(new Font("黑体", Font.PLAIN,16));
logbutton.setForeground(new Color(166,92,89));
backbutton=new JButton("后退");
backbutton.setFont(new Font("黑体", Font.PLAIN,16));
accountpanel=new JPanel();
// panel1布局
accountpanel.setLayout(new GridLayout(2,2,12,2));
// panel1添加各元素
accountpanel.add(accountlabel);
accountpanel.add(accountcount);
accountpanel.add(passwordlabel);
accountpanel.add(passwordcount);
// frame布局并将panel1添加至frame*部分
frame.setLayout(new BorderLayout());
frame.add(accountpanel, BorderLayout.CENTER);
//实例化panel2
passwordpanel=new JPanel(new GridLayout(1,2));
// panel2添加登陆和后退按钮
passwordpanel.add(logbutton);
passwordpanel.add(backbutton);
//将panel2添加至frame南部
frame.add(passwordpanel, BorderLayout.SOUTH);
//结脉设置大小、位置以及可视
frame.setSize(300,150);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//登陆以及后退按钮添加监听器
logbutton.addActionListener(this);
backbutton.addActionListener(this);
accountcount.setSize(30,30);
}
/*
*监听器方法 (non-Javadoc)
*
* @see
* java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
publicvoid actionPerformed(ActionEvent e){
//触发登陆
if(e.getSource()== logbutton){
try{
//控制输入输出流
BufferedReader br=new BufferedReader(new InputStreamReader(
client.socket.getInputStream()));
PrintWriter pw=new PrintWriter(
client.socket.getOutputStream());
//从界面中获取账号
String account= accountcount.getText();
//从界面中获取密码,并转化为字符串
char[] passwordlist= passwordcount.getPassword();
String password="";
for(int i =0; i< passwordlist.length; i++){
password+= passwordlist[i];
}
//向服务器发出登陆请求
pw.print("L");
pw.flush();
//向服务器传送账号
pw.println(account);
pw.flush();
//账号是否存在结果
String nameresult= br.readLine();
//账号存在
if(nameresult.equals("yes")){
//向服务器传送密码
pw.println(password);
pw.flush();
//接受服务器发来的检验结果
String passwordresult= br.readLine();
//检验结果为yes,也就是账号和密码匹配,就进入文件传输界面
if(passwordresult.equals("yes")){
new FileTransfer(br, pw);
}
//账号、密码不匹配
else{
//弹出对话框,提示密码错误
JOptionPane.showMessageDialog(null,"密码错误!","消息",
JOptionPane.WARNING_MESSAGE);
//将账号和密码框置为空
accountcount.setText("");
passwordcount.setText("");
}
}
//账号不存在
else{
JOptionPane.showMessageDialog(null,"该账号不存在!","消息",
JOptionPane.WARNING_MESSAGE);
//将账号和密码框置为空
accountcount.setText("");
passwordcount.setText("");
}
}catch(Exception ex){
ex.printStackTrace();
}
}
//触发后退按钮
elseif(e.getSource()== backbutton){
//登陆界面关闭
frame.dispose();
//新建主界面
new MainLog(client);
}
}
}
package Client;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
/*
*注册界面
*实现AcitonListener监听器
*/
publicclass Registerimplements ActionListener{
//界面
private JFrame frame;
//账号标签
private JLabel accountlabel;
//密码标签
private JLabel passwordlabel;
//确认密码标签
private JLabel checkpasswordlabel;
//账号框
private JTextField accountcount;
//密码框
private JPasswordField passwordcount;
//确认密码框
private JPasswordField passwordcheckcount;
//确认按钮
private JButton surebutton;
//后退按钮
private JButton backbutton;
//连接使用
Client client;
public Register(Client client){
//实例化以上元素
this.client= client;
frame=new JFrame("注册");
accountlabel=new JLabel("账号:");
accountlabel.setFont(new Font("黑体", Font.PLAIN,16));
passwordlabel=new JLabel("密码:");
passwordlabel.setFont(new Font("黑体", Font.PLAIN,16));
checkpasswordlabel=new JLabel("确认密码:");
checkpasswordlabel.setFont(new Font("黑体", Font.PLAIN,16));
accountcount=new JTextField();
passwordcount=new JPasswordField();
passwordcheckcount=new JPasswordField();
surebutton=new JButton("确认");
surebutton.setFont(new Font("黑体", Font.PLAIN,16));
surebutton.setForeground(new Color(166,92,89));
backbutton=new JButton("后退");
backbutton.setFont(new Font("黑体", Font.PLAIN,16));
//页面布局
frame.setLayout(new GridLayout(4,2));
//页面添加以上各元素
frame.add(accountlabel);
frame.add(accountcount);
frame.add(passwordlabel);
frame.add(passwordcount);
frame.add(checkpasswordlabel);
frame.add(passwordcheckcount);
frame.add(surebutton);
frame.add(backbutton);
//页面设置大小、位置以及可视
frame.setSize(300,180);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//确认按钮以及后退按钮添加监听器
surebutton.addActionListener(this);
backbutton.addActionListener(this);
}
/*
*监听器方法 (non-Javadoc)
*
* @see
* java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
publicvoid actionPerformed(ActionEvent e){
//触发确认按钮
if(e.getSource()== surebutton){
//从界面获取账号
String account= accountcount.getText();
//从界面获取密码并转为字符串形式
char[] password= passwordcount.getPassword();
String code="";
for(int i =0; i< password.length; i++){
code+= password[i];
}
//从界面获取确认密码并转为字符串形式
char[] passwordcheck= passwordcheckcount.getPassword();
String checkcode="";
for(int i =0; i< passwordcheck.length; i++){
checkcode+= passwordcheck[i];
}
//如果密码和确认密码不匹配
if(!code.equals(checkcode)){
//弹出对话框,提示密码输入有误
JOptionPane.showMessageDialog(null,"密码输入有误,请重新输入!","消息",
JOptionPane.WARNING_MESSAGE);
//密码框和确认密码框置为空
passwordcount.setText("");
passwordcheckcount.setText("");
}
//密码和确认密码匹配,则向服务器传去注册信号'R'
else{
try{
//实例化输入输出流
BufferedReader br=new BufferedReader(
new InputStreamReader(
client.socket.getInputStream()));
PrintWriter pw=new PrintWriter(
client.socket.getOutputStream());
//向服务器发出注册请求
pw.print('R');
pw.flush();
//向服务器传输账号
pw.println(account);
pw.flush();
//接受服务器传回的账号之前是否存在的检验结果
String exist= br.readLine();
//账号之前不存在
if(exist.equals("no")){
//向服务器发送密码
pw.println(code);
pw.flush();
//弹出注册成功的对话框
JOptionPane.showMessageDialog(null,"注册成功!");
}
//账号之前存在
else{
//弹出对话框,提示账号已存在
JOptionPane.showMessageDialog(null,"此账号已存在,请重新填写!",
"消息", JOptionPane.WARNING_MESSAGE);
//账号、密码、确认密码置为空
accountcount.setText("");
passwordcount.setText("");
passwordcheckcount.setText("");
}
}catch(Exception em){
em.printStackTrace();
}
}
}
//触发后退按钮
elseif(e.getSource()== backbutton){
//当前界面关闭
frame.dispose();
//新建主界面
new MainLog(client);
}
}
}
package Client;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
/*
*更改密码界面
*实现AcitonListener监听器
*/
publicclass ChangePasswordimplements ActionListener{
//界面
private JFrame frame;
//账号标签
private JLabel accountlabel;
//旧密码标签
private JLabel oldpasswordlabel;
//新密码标签
private JLabel newpasswordlabel;
//确认新密码标签
private JLabel checkpasswordlabel;
//账号框
private JTextField accountcount;
//旧密码密码框
private JPasswordField passwordoldcount;
//新密码框
private JPasswordField passwordnewcount;
//确认新密码框
private JPasswordField passwordcheckcount;
//确认按钮
private JButton surebutton;
//后退按钮
private JButton backbutton;
//连接用
Client client;
public ChangePassword(Client client){
//实例化以上元素
this.client=client;
frame=new JFrame("修改密码");
accountlabel=new JLabel("账号:");
accountlabel.setFont(new Font("黑体", Font.PLAIN,16));
oldpasswordlabel=new JLabel("原密码:");
oldpasswordlabel.setFont(new Font("黑体", Font.PLAIN,16));
newpasswordlabel=new JLabel("新密码:");
newpasswordlabel.setFont(new Font("黑体", Font.PLAIN,16));
checkpasswordlabel=new JLabel("确认密码:");
checkpasswordlabel.setFont(new Font("黑体", Font.PLAIN,16));
accountcount=new JTextField();
passwordoldcount=new JPasswordField();
passwordnewcount=new JPasswordField();
passwordcheckcount=new JPasswordField();
surebutton=new JButton("确认");
surebutton.setFont(new Font("黑体", Font.PLAIN,16));
surebutton.setForeground(new Color(166,92,89));
backbutton=new JButton("后退");
backbutton.setFont(new Font("黑体", Font.PLAIN,16));
//页面布局
frame.setLayout(new GridLayout(5,2,12,8));
//添加以上各元素
frame.add(accountlabel);
frame.add(accountcount);
frame.add(oldpasswordlabel);
frame.add(passwordoldcount);
frame.add(newpasswordlabel);
frame.add(passwordnewcount);
frame.add(checkpasswordlabel);
frame.add(passwordcheckcount);
frame.add(surebutton);
frame.add(backbutton);
//设置页面大小、位置以及可视
frame.setSize(320,200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//确认按钮、后退按钮添加监听器
surebutton.addActionListener(this);
backbutton.addActionListener(this);
}
/*
*监听器方法
* (non-Javadoc)
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
publicvoid actionPerformed(ActionEvent e){
//触发确认按钮
if(e.getSource()==surebutton){
//从界面获得账号
String account= accountcount.getText();
//从界面获得旧密码,并转为字符串形式
char[] code=passwordoldcount.getPassword();
String oldcode="";
for(int i =0; i< code.length; i++){
oldcode+= code[i];
}
//从界面获得新密码,并转为字符串形式
char[] newpassword= passwordnewcount.getPassword();
String newcode="";
for(int i =0; i< newpassword.length; i++){
newcode+= newpassword[i];
}
//从界面获得确认新密码,并转为字符串形式
char[] checkpassword= passwordcheckcount.getPassword();
String checkcode="";
for(int i =0; i< checkpassword.length; i++){
checkcode+= checkpassword[i];
}
//如果新密码和确认新密码不匹配
if(!newcode.equals(checkcode)){
//弹出对话框,提示密码输入有误
JOptionPane.showMessageDialog(null,"密码输入有误,请重新输入!","消息",JOptionPane.WARNING_MESSAGE);
//将新密码框和确认新密码框置为空
passwordnewcount.setText("");
passwordcheckcount.setText("");
}
//新密码和确认新密码匹配,向服务器传递修改密码信号'C'
else{
try{
//输入输出流
BufferedReader br=new BufferedReader(new InputStreamReader(client.socket.getInputStream()));
PrintWriter pw=new PrintWriter(client.socket.getOutputStream());
//向服务器发送更改密码的请求
pw.print('C');
pw.flush();
//向服务器发送账号
pw.println(account);
pw.flush();
//向服务器发送旧密码
pw.println(oldcode);
pw.flush();
//接受服务器返回的账号是否存在或密码是否正确的检验结果
String exist= br.readLine();
//账号密码匹配
if(exist.equals("yes")){
//向服务器发送新密码
pw.println(newcode);
pw.flush();
//弹出对话框,提示修改成功
JOptionPane.showMessageDialog(null,"修改成功!");
}
else{
//弹出对话框,提示账号不存在或密码错误
JOptionPane.showMessageDialog(null,"账号不存在或密码错误,请重新填写!","消息",JOptionPane.WARNING_MESSAGE);
//账号、旧密码、新密码、确认新密码置为空
accountcount.setText("");
passwordoldcount.setText("");
passwordnewcount.setText("");
passwordcheckcount.setText("");
}
}catch(Exception em){
em.printStackTrace();
}
}
}
//触发后退按钮
elseif(e.getSource()==backbutton){
//当前界面关闭
frame.dispose();
//新建主界面
new MainLog(client);
}
}
}
FileTransfer包:
package FileTransfer;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
/*
*登陆后的操作总界面,含上传下载两个按钮
*操作总界面实现ActionListener接口
*/
publicclass FileTransferimplements ActionListener{
//界面构成:
// frame窗体
private JFrame frame;
private JPanel panel;
//上传按钮
private JButton uploadbutton;
//下载按钮
private JButton downloadbutton;
//从服务器读取的读入流
BufferedReader br;
//向服务器传送的输出流
PrintWriter pw;
public FileTransfer(BufferedReader br, PrintWriter pw){
//输入输出流实例化
this.br= br;
this.pw= pw;
//操作界面实例化
frame=new JFrame("文件上传与下载");
panel=new JPanel(new GridLayout(2,1));
uploadbutton=new JButton("上传");
downloadbutton=new JButton("下载");
frame.setLayout(new BorderLayout());
frame.add(panel, BorderLayout.CENTER);
// panel界面布局
panel.setLayout(new GridLayout(2,1));
// panel界面添加按钮
panel.add(uploadbutton);
panel.add(downloadbutton);
//操作界面设定大小、位置以及可视
frame.setSize(300,150);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
//上传按钮添加监听器
uploadbutton.addActionListener(this);
//下载按钮添加监听器
downloadbutton.addActionListener(this);
}
/*
* ActionListener接口方法 (non-Javadoc)
*
* @see
* java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
publicvoid actionPerformed(ActionEvent e){
//上传按钮监听,触发后进行上传功能,新建下载界面
if(e.getSource()== uploadbutton){
new Upload(br, pw);
}
//下载按钮监听,触发后进行下载功能,新建下载界面
elseif(e.getSource()== downloadbutton){
new Download(br, pw);
}
}
}
package FileTransfer;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.PrintWriter;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import Client.Client;
/*
*上传界面
*/
publicclass Upload{
//界面
JFrame frame;
//普通panel
JPanel panel;
//上传按钮
JButton uploadbutton;
//上传路径显示标签
JLabel uploadlabel;
//进度条
JProgressBar progressbar;
public Upload(BufferedReader br, PrintWriter pw){
//以上各元素实例化及布局
frame=new JFrame("上传界面");
frame.setLayout(new BorderLayout());
progressbar=new JProgressBar();
progressbar.setOrientation(JProgressBar.HORIZONTAL);
progressbar.setMaximum(100);
progressbar.setMinimum(0);
progressbar.setValue(0);
progressbar.setStringPainted(true);
frame.add(progressbar, BorderLayout.SOUTH);
panel=new JPanel(new GridLayout(5,2));
frame.add(panel, BorderLayout.CENTER);
uploadlabel=new JLabel();
panel.add(uploadlabel);
uploadbutton=new JButton("上传");
uploadbutton.addActionListener(new UploadListener(uploadlabel,
progressbar, br, pw));
panel.add(uploadbutton);
frame.setSize(500,200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class UploadListenerimplements ActionListener{
//文件路径标签
JLabel filenamelabel;
//进度条
JProgressBar progressbar;
//控制信息传输IO流
BufferedReader br;
PrintWriter pw;
//文件选择器
JFileChooser fchooser;
//从本地文件读出的IO流
DataOutputStream os;
public UploadListener(JLabel filenamelabel, JProgressBar progressbar,
BufferedReader br, PrintWriter pw){
this.filenamelabel= filenamelabel;
this.progressbar= progressbar;
this.br= br;
this.pw= pw;
}
publicvoid actionPerformed(ActionEvent e){
new Thread(new Runnable(){
publicvoid run(){
try{
//
pw.print('U');
pw.flush();
//文件输出流
Client client=new Client(6666);
os=new DataOutputStream(client.socket.getOutputStream());
//打开文件选择对话框
fchooser=new JFileChooser();
int openResult= fchooser.showOpenDialog(null);
if(openResult== JFileChooser.APPROVE_OPTION){
fchooser.setToolTipText(fchooser.getSelectedFile()
.getName());
//获取文件绝对路径
String fpath= fchooser.getSelectedFile()
.getAbsolutePath();
//实例化所选文件
File f=new File(fpath);
//向服务器发送文件名字
os.writeUTF(f.getName());
os.flush();
//文件总长度
int length=(int) f.length();
//文件已传输长度
int passlen=0;
//文件读入流
DataInputStream fis=new DataInputStream(
new BufferedInputStream(new FileInputStream(f)));
//构造文件读入缓冲数组buf,长度为8192,类型为byte
int bufferSize=8192;
byte[] buf=newbyte[bufferSize];
//循环读取并发送,直至读完
while(true){
//每次读取长度的read
int read=0;
//读入流不为空,则能获取本次读到的长度
if(fis!=null){
read= fis.read(buf);
}
//如果此次读到的长度为-1,证明读空,需要跳出循环,不再从文件读入
if(read==-1){
break;
}else{
//进度条显示已传输的百分比
passlen+= read;
progressbar.setValue(passlen*100/ length);
}
//将每次读到缓冲数组里的内容读到文件输出流中
os.write(buf,0, read);
}
//将输出流中内容发送给服务器
os.flush();
//前置标签上写上文件路径
filenamelabel.setText(fpath);
filenamelabel.repaint();
filenamelabel.validate();
//关闭文件内容传输socket连接以及各种输入输出流
fis.close();
client.socket.close();
JOptionPane.showMessageDialog(null,"文件上传完成!");
}
}catch(Exception ex){
ex.printStackTrace();
}
}
}).start();
}
}
package FileTransfer;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import Client.Client;
/*
*下载界面
*/
publicclass Download{
//界面构成:
// frame窗体
JFrame frame;
//显示文件名的标签
JLabel[] filelabel;
//下载按钮
JButton[] downloadbutton;
//有滚动条的Panel
JScrollPane scroll;
//普通panel
JPanel panel;
//
JProgressBar progressbar;
public Download(BufferedReader br, PrintWriter pw){
//实例化输入输出流
try{
//向服务器发出传输服务器段文件存在情况的请求
pw.println('S');
pw.flush();
//从服务器获取文件的个数
int fileno= Integer.parseInt(br.readLine());
//将标签以及按钮实例化
filelabel=new JLabel[fileno];
downloadbutton=new JButton[fileno];
//实例化frame
frame=new JFrame("下载界面");
//布局
frame.setLayout(new BorderLayout());
progressbar=new JProgressBar();
progressbar.setOrientation(JProgressBar.HORIZONTAL);
progressbar.setMaximum(100);
progressbar.setMinimum(0);
progressbar.setValue(0);
progressbar.setStringPainted(true);
frame.add(progressbar, BorderLayout.SOUTH);
//实例化panel
panel=new JPanel(new GridLayout(fileno+1,2));
// panel添加两栏标题
panel.add(new JLabel("文件名", JLabel.CENTER));
panel.add(new JLabel("下载", JLabel.CENTER));
//实例化scroll
scroll=new JScrollPane(panel);
//循环从服务器段读取文件标题添加至界面,并添加相应的按钮
for(int i =0; i< fileno; i++){
//实例化对应标签
filelabel[i]=new JLabel(br.readLine(), JLabel.CENTER);
//添加标签
panel.add(filelabel[i]);
//实例化对应按钮
downloadbutton[i]=new JButton("下载");
//为按钮添加监听器
downloadbutton[i].addActionListener(new DownLoadListener(
progressbar, filelabel[i].getText(), br, pw));
//添加按钮
panel.add(downloadbutton[i]);
}
//在必要时显示垂直滚动条
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
//添加scroll
frame.add(scroll, BorderLayout.CENTER);
//设置界面大小、位置及可视
frame.setSize(500,400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}catch(Exception e){
e.printStackTrace();
}
}
}
/*
*下载按钮监听器
*/
class DownLoadListenerimplements ActionListener{
//进度条
JProgressBar progressbar;
//要下载文件名
String filename;
//输入输出流
BufferedReader br;
PrintWriter pw;
DataInputStream is;
//文件传输用的client(内含socket)
Client client;
//文件选择器
JFileChooser filechooser;
public DownLoadListener(JProgressBar progressbar, String filename,
BufferedReader br, PrintWriter pw){
//各项内容实例化
this.progressbar= progressbar;
this.filename= filename;
this.br= br;
this.pw= pw;
}
//监听器方法
publicvoid actionPerformed(ActionEvent e){
new Thread(new Runnable(){
publicvoid run(){
try{
//向服务器发出下载文件的请求
pw.print('D');
pw.flush();
//向服务器传送文件名
pw.println(filename);
pw.flush();
client=new Client(6666);
//读取文件内容输入流
is=new DataInputStream(new BufferedInputStream(
client.socket.getInputStream()));
//
int length=(int) is.readLong();
//已接受文件长度
int passlen=0;
//实例化filechooser
filechooser=new JFileChooser();
//只给出文件夹的位置
filechooser
.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int openResult= filechooser.showSaveDialog(null);
if(openResult== JFileChooser.APPROVE_OPTION){
filechooser.setToolTipText(filechooser
.getSelectedFile().getName());
//生成文件路径
String filepath= filechooser.getSelectedFile()
.getAbsolutePath()+"/"+ filename;
//写入文件的输出流
DataOutputStream dos=new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(
filepath)));
//缓存数组,存放从服务器端发送的内容,长度为8192,类型为byte
int bufferSize=8192;
byte[] buf=newbyte[bufferSize];
//循环读取,直至从服务器传送的内容为空
while(true){
//每次读取的长度
int read=0;
//流内还有内容,read即有数目
if(is!=null){
read= is.read(buf);
}
// read=-1表明流内读空,可以跳出循环
if(read==-1){
break;
}else{
try{
Thread.sleep(10);
}catch(Exception ex){
ex.printStackTrace();
}
passlen+= read;
progressbar.setValue(passlen*100/ length);
}
//将buf内容写到dos中
dos.write(buf,0, read);
}
//将所读内容传到服务器
dos.flush();
JOptionPane.showMessageDialog(null,"文件下载完成!");
//关闭各项IO流以及文件传输socket
dos.close();
client.socket.close();
}else{
filechooser.setToolTipText("you select cancel");
}
}catch(Exception ex){
ex.printStackTrace();
}
}
}).start();
}
}