首页 > 代码库 > JAVA学习第六十二课 — TCP协议练习

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

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


练习1:创建一个英文大写转换服务器

客户端输入字母数据,发送给服务端,服务端收到后显示到控制台,并将该数据转成大写返回客户端,知道客户端输入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,读取客户端发过来需要转换的数据
		 * 4.汇:显示在控制台
		 * 5.将数据转成大写返回客户端
		 */
		//创建服务端对象
		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+"\r\n");
		}                                      //pw.flush();
		socket.close();
		ss.close();
	}

	public static void Text_Transform_Client() throws IOException{
		//文本转换客户端
		/*
		 * 转换客户端:
		 * 1.创建Socket客户端对象
		 * 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+"\r\n")
			                 //pw.flush();
			//读取服务端返回的大写信息
			String str = br2.readLine();
			System.out.println("up : "+str);
		}
		socket.close();
	}
}

常见问题:

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

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


二、如果在客户端和服务端的PrintWriter pw = new PrintWriter(socket.getOutputStream())的自动刷新去掉,pw.print()的自动换行去掉,会发生什么?

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

因为在客户端,pw.print()写入的数据,都写到了PrintWriter中,并没有刷新到socket输入流中

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

当然,可以在pw.print();下加pw.flush(),但是问题依旧,因为readline读取结束的标记是换行,所以在客户端的pw.print(+"\r\n"),所以要想 解决问题,就要在客户端和服务端都加上刷新动作,和换行符。

一旦遇到上述问题,一般都是因为阻塞式方法造成的服务端、客户端都在等待的情况,所以按照上述代码示例所写,比较好


练习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();
	}
}

*号处要注意,漏写容易造成,等待清理,客户端输入完毕后,服务端还在等待,不知道客户端已经输入完毕,阻塞,等待

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

练习3:上传图片

上传图片到客户端

public static void main(String[] args)throws IOException{
		UpText_Client();
	}
	public static void UpText_Client() throws IOException {
	
		//创建客户端
		Socket socket = new Socket("127.0.0.1",6534);
		
		//读取客户端要上传的图片文件
		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);
		}
		
		//告诉服务端,客户端数据发送完毕,使其读取结束
		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);
		
		//获取客户端
		Socket socket = ss.accept();
		//读取客户端发来的数据
		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();
	}

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

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


服务端结合线程,改进

客户端部分不变

服务端

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();//不停的接收客户端对象
			new Thread(new UPtask(socket)).start();//创建多个线程执行不同客户端的信息
		}
	}
}

服务端线程

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("服务器异常,请稍等");
		}
	}
}





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