6.服务器与客户端双线程传输文件--服务器端

/*
 * 本程序主要功能:
 * 服务器端,双线程传输文件
 * 其中一个线程向客户端发送文件,一个线程从客户端下载文件
 * 
 */

import java.io.*;//这里使用BufferedOutputStream,BufferedReader,IOException,OutputStream
import java.net.*;//这里使用ServerSocket,Socket 类

public class TestFileServer_1 
{

	public final int DEFAULT_PORT = 8000;//Server默认端口号:8000
	public ServerSocket serverSocket;//新建一个ServerSocke成员属性:serverSocket
	public Socket server;//新建一个Socket成员属性:server
	public SendFile sf;//新建一个对象SendFile成员属性:sf
	public GetFile gf;//新建一个GetFile成员属性:gf
	
	void start()//方法:启动服务
	{
		try
		{
			serverSocket = new ServerSocket(DEFAULT_PORT);//通过DEFAULT_PORT,创建一个ServerSocket对象:serverSocket
			System.out.println("Server start successfully!");//提示信息:服务器成功启动
			System.out.println("waiting for client's connection...");//提示信息:等待客户端连接
			server = serverSocket.accept();//若客户端成功连接,则返回Socket对象,赋值给Server
			if(true)
			{

				sf = new SendFile(server);//通过server,创建一个SendFile对象:sf
				gf = new GetFile(server);//通过server,创建一个GetFile对象:gf
				
				sf.start();//启动sf对应的SendFile线程
				gf.start();//启动gf对应的GetFile线程
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		
	}	
	public static void main(String[] args) 
	{
		// TODO 自动生成的方法存根

		TestFileServer_1 tfs = new TestFileServer_1();//创建一个TestFileServer_1对象:tfs
		
		tfs.start();//tfs启动服务
	}

}
class SendFile extends Thread
{
	public Socket server;//新建一个Socket成员属性:client	
	public FileInputStream fileInput;//新建一个InputStream成员属性:fileInput
	public DataOutputStream fileOutput;//新建一个OutputStream成员属性:fileOutput
	public byte[] buf;
	
	public SendFile(Socket server)
	{
		this.server = server;//将形参client赋值给属性client
		
		try
		{
			buf = new byte[1024];//创建byte数组大小为1024个字节
			fileOutput = new DataOutputStream(//创建一个数据输出流
					new BufferedOutputStream(//创建一个缓冲输出流
							server.getOutputStream()));//获取server的输出流
			fileInput = new FileInputStream(new File("isServer.pdf"));//创建一个文件输入流,获取文件isServer.pdf的内容
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}
	
	@Override//重写标记
	public void run()//实现run方法
	{
		try
		{
		
			/*开始发送文件*/
			int num = fileInput.read(buf);//从此输入流中将最多 buf.length个字节的数据读入一个 buf数组中。返回:读入缓冲区的字节总数			
			while(num != -1)//如果因为已经到达文件末尾而没有更多的数据,则返回 -1。
			{
				fileOutput.write(buf, 0, num);//将buf数组中从0 开始的num个字节写入此文件输出流。
				num = fileInput.read(buf);//从此输入流中将最多 buf.length个字节的数据读入一个 buf数组中。返回:读入缓冲区的字节总数
				fileOutput.flush();//刷新输出缓冲区,并强制将输出缓冲区所有字节写出至目的地址					
			}
			
			/*关闭流处理*/
			fileInput.close();//关闭fileInput流
			server.shutdownOutput();//禁用server的输出流。
									//注意:这里不能使用OutputStream.close()方法。
									//因为OutputStream.close()方法会将Socket关闭,使得GetFile线程造成异常
									//也不能不进行关闭,因为不关闭会造成阻塞,无法正常使用GetFile的run()方法	
			
		}
		catch(Exception e)
		{
			e.printStackTrace();
			try
			{
				if(fileInput != null)
				{
					fileInput.close();//异常时,如果已经打开了fileInput,则关闭
				}							
				if(fileOutput != null)
				{
					fileOutput.close();//异常时,如果已经打开了fileOutput,则关闭
				}
			}
			catch(Exception e1)
			{
				e1.printStackTrace();
			}
		}
	}
}

class GetFile extends Thread
{
	public Socket server;//新建一个Socket成员属性:server	
	public DataInputStream fileInput;//新建一个InputStream成员属性:fileInput
	public File file;//新建一个File成员属性:file
	public RandomAccessFile rf;//新建一个RandomAccessFile成员属性:rf
	byte[] buf;//新建一个字节数组成员属性:buf
	
	public GetFile(Socket server)
	{
		this.server = server;//将形参server赋值给属性server

		try
		{
			buf = new byte[1024];//创建byte数组大小为1024个字节
			file = new File("fromClient.pdf");//通过文件名"fromClient.pdf",创建一个File对象:file		
			file.createNewFile();//当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。
			rf = new RandomAccessFile(file,"rw");//通过file,创建从中读取和向其中写入的随机访问文件流对象:rf。
												//"rw" 打开以便读取和写入。如果该文件尚不存在,则尝试创建该文件。 
			fileInput = new DataInputStream(//创建一个数据输入流
					new BufferedInputStream(//创建一个缓冲输入流
							this.server.getInputStream()));//获取server的输出流
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
	}

	@Override
	public void run()
	{
		try
		{
			System.out.println("Downloading File...");//提示信息:下载文件中...			

			/*开始下载文件*/
			int num = fileInput.read(buf);//从此输入流中将最多 buf.length个字节的数据读入一个 buf数组中。返回:读入缓冲区的字节总数			
			while(num != -1)//如果因为已经到达文件末尾而没有更多的数据,则返回 -1
			{				
					rf.write(buf, 0, num);//将buf数组中从0 开始的num个字节写入此文件输出流
					rf.skipBytes(num);//跳过num个字节数
					num = fileInput.read(buf);//从此输入流中将最多 buf.length个字节的数据读入一个 buf数组中。返回:读入缓冲区的字节总数
							
			}
			
			/*关闭流处理*/
			rf.close();//关闭RandomAccessFile流
			server.shutdownInput();//禁用server的输入流。
									//注意:这里不能使用InputStream.close()方法。
									//因为InputStream.close()方法会将Socket关闭,使得SendFile线程造成异常
									//也不能不进行关闭,因为不关闭会造成阻塞,无法正常使用SendFile的run()方法
			
			System.out.println("Downloading Completely");//提示信息:下载完成
		}
		catch(Exception e)
		{
			e.printStackTrace();
			
			try
			{
				if(fileInput != null)
				{
					fileInput.close();//异常时,如果已经打开了fileInput,则关闭
				}
			}
			catch(Exception e1)
			{
				e1.printStackTrace();
			}
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值