• JAVA学习第六十二课 — TCP协议练习


    通过练习掌握TCP在进行传输过程中的问题


    练习1:创建一个英文大写转换server

    client输入字母数据,发送给服务端,服务端收到后显示到控制台,并将该数据转成大写返回client,知道client输入over,转换结束

    public class Main {
    	
    	public static void main(String[] args) throws IOException{
    		Text_Transform_Client();
    		Text_Transform_Server();
    	}
    
    	public static void Text_Transform_Server() throws IOException {
    		//文本转服务端
    		
    		/* 转换服务端
    		 * 1.创建ServerSocket服务端对象
    		 * 2.获取Socket对象
    		 * 3.源:Socket,读取client发过来须要转换的数据
    		 * 4.汇:显示在控制台
    		 * 5.将数据转成大写返回client
    		 */
    		//创建服务端对象
    		ServerSocket ss = new ServerSocket(6534);
    		
    		//获取socket对象
    		Socket socket = ss.accept();
    		
    		//获取ip,明白是谁连进来的
    		String ip = socket.getInetAddress().getHostAddress();
    		System.out.println("ip : "+ip);
    		
    		//获取socket读取流,并装饰
    		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    		//获取socket输出流,并装饰
    		PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
    		                      //new PrintWriter(socket.Outputtream())
    		String line = null;
    		while((line = br.readLine())!=null){
    			System.out.println(line);
    			pw.println(line.toUpperCase());//pw.print(line.tpUpperCase+"
    ");
    		}                                      //pw.flush();
    		socket.close();
    		ss.close();
    	}
    
    	public static void Text_Transform_Client() throws IOException{
    		//文本转换client
    		/*
    		 * 转换client:
    		 * 1.创建Socketclient对象
    		 * 2.获取键盘录入
    		 * 3.将录入的信息,发送给Socket输出流
    		 */
    		Socket socket = new Socket("127.0.0.1",6534);
    		BufferedReader br = 
    				new BufferedReader(new InputStreamReader(System.in));
    		
    		//源是:键盘,汇:Socket输出流
    		//new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    		PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
    		                                  //new PrintWriter(socket.getOutstream());
    		//Socket输入流,读取服务端返回的大写数据
    		BufferedReader br2 = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    		
    		String line = null;
    		while((line = br.readLine())!=null){
    			if("over".equals(line))break;
    			
    			pw.println(line);//pw.print(line+"
    ")
    			                 //pw.flush();
    			//读取服务端返回的大写信息
    			String str = br2.readLine();
    			System.out.println("up : "+str);
    		}
    		socket.close();
    	}
    }

    常见问题:

    一、上述代码有一个问题,就是client输入over后client结束,服务端有没有结束?

        结束,readline()方法是堵塞式方法,可是在client输入over后,client的socket关闭返回一个-1,服务端的readline()方法中的read方法读取-1,所以readline()方法就读取到null,所以会结束。


    二、假设在client和服务端的PrintWriter pw = new PrintWriter(socket.getOutputStream())的自己主动刷新去掉,pw.print()的自己主动换行去掉,会发生什么?

       client没有收到转换后的数据,服务端没有显示数据

    由于在client,pw.print()写入的数据,都写到了PrintWriter中,并没有刷新到socket输入流中

    PS:这就是TCP在传输过程中出现两端都在等待的情况,非常可能是数据没有发出去,最大的可能就是有堵塞式方法。

    当然,能够在pw.print();下加pw.flush(),可是问题依然,由于readline读取结束的标记是换行,所以在client的pw.print(+" "),所以要想 解决这个问题,就要在client和服务端都加上刷新动作,和换行符。

    一旦遇到上述问题,一般都是由于堵塞式方法造成的服务端、client都在等待的情况,所以依照上述代码演示样例所写,比較好


    练习2:上传文本文件

    public class Main {
    	
    	public static void main(String[] args)throws IOException{
    		UpText_Client();
    		UpText_Server();
    	}
    
    	public static void UpText_Server() throws IOException {
    		
    		ServerSocket ss = new ServerSocket(6534);
    		Socket socket = ss.accept();
    		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    		
    		BufferedWriter bw = new BufferedWriter(new FileWriter("c:\server.txt"));
    		
    		String line = null;
    		while((line = br.readLine())!=null){
    			//if("over".equals(line))break;//*
    			bw.write(line);
    			bw.newLine();//*
    			bw.flush();//*
    		}
    		
    		PrintWriter pw = new PrintWriter(socket.getOutputStream(),true);
    		pw.println("上传成功");
    		
    		br.close();
    		bw.close();
    		socket.close();
    		ss.close();
    	}
    
    	public static void UpText_Client() throws IOException {
    		
    		Socket socket = new Socket("127.0.0.1",6534);
    		BufferedReader br = new BufferedReader(new FileReader("c:\data.txt"));
    		PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
    		String line = null;
    		while((line = br.readLine())!=null){
    			out.println(line);
    		}
    		//out.println("over");//*,开发的时候一般都是应用时间戳,做结束标记,先发给服务器一下时间戳,输入结束后,再发一次
    		//socket里有方法
    		socket.shutdownOutput();//告诉服务端数据写完了
    		
    		//读取socket流
    		BufferedReader brin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    		String string = brin.readLine();
    		System.out.println(string);
    		br.close();
    		socket.close();
    	}
    }

    *号处要注意,漏写easy造成,等待清理,client输入完成后,服务端还在等待,不知道client已经输入完成,堵塞,等待

    演示的时候,分为两个主函数演示

    练习3:上传图片

    上传图片到client

    public static void main(String[] args)throws IOException{
    		UpText_Client();
    	}
    	public static void UpText_Client() throws IOException {
    	
    		//创建client
    		Socket socket = new Socket("127.0.0.1",6534);
    		
    		//读取client要上传的图片文件
    		FileInputStream fis = new FileInputStream("c:\1.jpg");
    		
    		//获取socket输出流,将得到的图片数据发给服务端
    		OutputStream out = socket.getOutputStream();
    		byte[] buf = new byte[1024];
    		int len = 0;
    		while((len = fis.read(buf))!=-1){
    			out.write(buf, 0, len);
    		}
    		
    		//告诉服务端,client数据发送完成,使其读取结束
    		socket.shutdownOutput();
    		
    		InputStream in = socket.getInputStream();
    		byte[] buf2 = new byte[1024];
    		int len2 = in.read(buf2);
    		String result = new String(buf2,0,len2);
    		System.out.println(result);
    		socket.close();
    		fis.close();
    		
    	}


    上传图片到服务端

    public static void main(String[] args)throws IOException {
    		UpText_Server();
    	}
    	public static void UpText_Server() throws IOException {
    		//创建服务端
    		ServerSocket ss = new ServerSocket(6534);
    		
    		//获取client
    		Socket socket = ss.accept();
    		//读取client发来的数据
    		InputStream in = socket.getInputStream();
    		
    		String ip = socket.getInetAddress().getHostAddress();
    		System.out.println("IP : "+ip+"....connect");
    		//将读取的数据存储到文件里
    		File dir = new File("c:\CopyPic111111111");
    		if (!(dir.exists())) {
    			dir.mkdirs();
    		}
    		File file = new File(dir,ip+".jpg");
    		FileOutputStream fos = new FileOutputStream(file);
    		
    		byte[] buf = new byte[1024];
    		int len = 0;
    		while((len = in.read(buf))!=-1){
    			fos.write(buf, 0, len);
    		}
    		//获取socket输出流,显示上传结果
    		OutputStream out  = socket.getOutputStream();
    		out.write("上传成功".getBytes());
    		fos.close();
    		socket.close();
    		ss.close();
    	}

    上述代码的服务端仅仅能获取一个client上传,多个则不行。

    服务端获取了1号client正在处理1号client,那么2号client就必需要等待,等待时间过长,就会连接超时,所以服务端结合线程,获取client对象为一个线程,处理client信息为一个线程,不停的切换,就能够实现多个client上传图片到服务端


    服务端结合线程,改进

    client部分不变

    服务端

    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    public class Up {
    
    	private static ServerSocket ss;
    	public static void main(String[] args)throws IOException {
    		UpText_Server();
    	}
    	public static void UpText_Server() throws IOException {
    		
    		ss = new ServerSocket(6534);
    		
    		while(true){
    			Socket socket = ss.accept();//不停的接收client对象
    			new Thread(new UPtask(socket)).start();//创建多个线程运行不同client的信息
    		}
    	}
    }

    服务端线程

    public class UPtask implements Runnable {
    	private Socket socket;
    	public UPtask(Socket socket){
    		this.socket = socket;
    	}
    	public void run() {
    		int count = 1;
    		try {
    		String ip = socket.getInetAddress().getHostAddress();
    		System.out.println("IP : "+ip+"....connect");
    		InputStream in = socket.getInputStream();
    	
    		  File dir = new File("c:\CopyPic111111111");
    			if (!(dir.exists())) {
    				dir.mkdirs();
    			}
    			File file = new File(dir,ip+".jpg");
    			//假设已经存在
    			while(file.exists()) {
    				file = new File(dir,ip+"("+(count++)+").jpg");
    			}
    			FileOutputStream fos = new FileOutputStream(file);
    			
    			byte[] buf = new byte[1024];
    			int len = 0;
    			while((len = in.read(buf))!=-1){
    				fos.write(buf, 0, len);
    			}
    			//获取socket输出流,显示上传结果
    			OutputStream out  = socket.getOutputStream();
    			out.write("上传成功".getBytes());
    			fos.close();
    			socket.close();
    		} catch (Exception e) {
    			// TODO: handle exception
    			throw new RuntimeException("server异常,请稍等");
    		}
    	}
    }
    


    UDP和TCP的差别:

    UDP:将数据打包,有限制,不连接,效率高,不安全,easy丢包
    TCP:建立数据通道,无限制,效率低,安全



  • 相关阅读:
    在LinuxMint 17 MATE中安装NVIDIA显卡驱动
    如何在VeryCD中下载资源
    创建多个Dialog时,namespace冲突问题的解决 -- 基于QT 5.2
    Qt 5.2中编译加载MySQL数据库驱动问题的总结
    Python入门 -- 001
    Qt 入门 ---- 布局管理
    Qt 入门 ---- 如何在程序窗口显示图片?
    Redis 教程笔记
    Python pip 报错
    Python手动安装 package
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/4550389.html
Copyright © 2020-2023  润新知