网络通信--TCP

要实现的功能:
完成一个文件服务器,要求服务端能够共享一个本地目录,目录中包含一些纯文件(不包含子目录),客户端连接服务器之后可以在客户端显示目录中的文件列表(每个文件都有一个编号),当客户端输入一个文件编号后,可以将文件列表中的某个文件下载到客户端(无需手动在客户端指定文件名)。

思维过程:

服务端:
2.从磁盘里面读出文件;
3.发送文件名列表到socket对象里面;
6.从socket对象中读取文件编号;
7.根据编号得到找到相应的文件发送文件到socket对象中;

客户端:
1.和服务端建立连接(ip/port);
4.从socket对象中读取文件名列表;
5.发送需要下载的文件编号到socket对象;
8.从socket对象中接收文件;
9.将文件写入到磁盘文件.

用到的知识:
1.面向对象
2.io流
3.多线程
4.网络编程socket
5.集合(map.list.set)

里面自己要注意的一些操作:
1.首先是服务器要从磁盘里面读入某个文件夹里面的所有文件,
就存在多个文件对象,我们不可能手动一个个去读写,很麻烦,
所以想到了对象的序列化和反序列化将文件夹下的所有文件放入到一个集合里面去,
然后读写去操作这个集合对象,又因为要对文件夹下面的每个文件进行编号,所以使用map集合(键值对的形式)
2.因为服务端不可能只和一个客户端打交道,因此要用到多线程,所以当服务器开启后,每进来一个客户端,就相当于一个线程,创建一个新socket对象,去下载服务器上指定文件夹下的客户想下载的文件
3.服务端和客户端之间的交互是通过socket对象来,文件数据的传递都是通过对socket的读写来得到的.
4.还需要注意的就是java基础里面的各种细节上的知识,和java面向对象特征的体现(构造器,代码的封装,异常)

/**
 * 
 * @author dch
 *
 */
//服务端(多线程)
public class Server extends Thread {

	//socket对象
	private Socket s;
	//
	private String sourceDir;
	
	public Server(Socket s , String sourceDir){
		super();
		this.s = s;
		this.sourceDir = sourceDir;
	}
	
	//重写run方法
		@Override
		public void run() {
			//1.读取目录中的标准文件列表
			//2.将文件名列表传输到socket
			//3.接收文件编号的指令
			//4.通过文件编号找到文件传输到socket中
			try {
				//获取基于socket的输出流
				HashMap<Integer, String> map = tomap(sourceDir);
				OutputStream os= s.getOutputStream();
				sendObject(os, map);
				int num = readCommond();
				System.out.println(num);
				String fname = map.get(num);
				System.out.println(fname);
				//根据源目录以及文件名获取到一个文件对象
				File file = new File(sourceDir,fname);
				//发送文件
				send(file);
			}catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}finally{
				try {
					s.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		
		private void send(File file) throws Exception {
			// TODO Auto-generated method stub
			//获取源文件的输入流对象
			BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
			//获取Socket的输出流
			BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());
			//
			byte [] b = new byte[1024];
			int len = 0;
			while((len=bis.read(b))!=-1){
				bos.write(b, 0, len);
			}
			bis.close();
			bos.close();
		}

		private int readCommond() throws Exception {
			// TODO Auto-generated method stub
			//BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			InputStream is = s.getInputStream();
			System.out.println("1234");
			//String com = br.readLine();
			//System.out.println("1234");
			//Utils.msg("--"+com);
			return is.read();
		}

		

		private void sendObject(OutputStream os,HashMap<Integer, String> map) throws Exception{
			//对象序列化
			ObjectOutputStream oos = new ObjectOutputStream(os);
			//写入对象
			oos.writeObject(map);
			//关流
			oos.flush();
			
		}
		
		
	
		public HashMap<Integer, String> tomap(String path){
			//封装成文件对象
			File dir = new File(path);
			File [] files = dir.listFiles(new MyFileFilter());
			/*File [] files = dir.listFiles((File f)->{
				return f.isFile();
			});*/
			HashMap<Integer, String> map = new HashMap<Integer, String>();
			for (int i = 0; i < files.length; i++) {
				map.put(i+1, files[i].getName());
			}
			/*Set<Integer> set = map.keySet();
			for (Integer i : set) {
				Utils.msg(i+"----"+map.get(i));
			}*/
			return map;
		}
		
	//主方法
	public static void main(String[] args) throws Exception {
		
		//声明需要共享的目录
		String dir = "d://测试文件夹//a";
		ServerSocket ss = new ServerSocket(7777);
		Utils.msg("服务已启动");
		while(true){
			Socket s = ss.accept();
			Utils.msg("客户端连接成功:"+s.getInetAddress().getHostAddress());
			//开始提供服务
			/*Server server = new Server(s);
			server.start();*/
			new Server(s, dir).start();
		}
	}
}



/**
 * 
 * @author dch
 *
 */
//客户端
public class Client {

	//socket对象
	private Socket s;
	//获取文件名
	private String basePath;
	
	//构造器
	public Client(Socket s, String basePath) {
		super();
		this.s = s;
		this.basePath = basePath;
	}

	public  void download() {
		
		//1.接收文件夹
		//2.发送需要下载的文件编号
		//3.接收文件
		try {
			HashMap<Integer, String> map = getFileInfo(s.getInputStream());
			Set<Integer> set = map.keySet();
			for (Integer i : set) {
				Utils.msg(i+"--"+map.get(i));
			}
			Utils.msg("请输入需要下载的文件编号:");
			int num = getInputAndSend();
			//根据 文件编号得到文件名
			String fname = map.get(num);
			System.out.println(fname);
			//得到源目录以及文件名
			File file = new File(basePath,fname);
			reciver(file);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	//接收文件
	private void reciver(File file) throws Exception {
		// TODO Auto-generated method stub
		//获取基于scoket的输入流(包含文件信息)
		BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
		//
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
		byte [] b = new byte[1024];
		int len = 0; 
		Utils.msg("开始下载!");
		while((len=bis.read(b))!=-1){
			bos.write(b, 0, len);
		}
		Utils.msg("下载完成!");
		bos.close();
		bis.close();
	}

	//获取输入到的编号并发送到服务端
	private int getInputAndSend() {
		// TODO Auto-generated method stub
		int num=0;
		Scanner sc = new Scanner(System.in);
		try {
			//这个输入文件编号可能报错
			num = sc.nextInt();
			//获取基于socket的输出流并包装
			//PrintWriter pw = new PrintWriter(s.getOutputStream());
			OutputStream os = s.getOutputStream();
			os.write(num);
			//pw.flush();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			Utils.msg("请输入正确的文件编号!");
			return getInputAndSend();
		}
		return num;
	}

	//从输入流获取一个Map集合对象
	private HashMap<Integer, String> getFileInfo(InputStream inputStream) throws Exception {
		// TODO Auto-generated method stub
		ObjectInputStream ois = new ObjectInputStream(inputStream);
		Object obj =  ois.readObject();
		return obj != null ? (HashMap<Integer, String>)obj : null;
	}

	public static void main(String[] args) throws Exception{
		//声明要下载到的文件夹名字(字符串路径)
		String basePath = "d://测试文件夹//b"; 
		//连接服务端
		Socket s = new Socket("192.168.3.115",7777);
		//创建客户端对象并代用dowmload方法
		new Client(s, basePath).download();
	}
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值