通过练习掌握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("服务器异常,请稍等"); } } }