Tcp传输应用

Tcp传输应用

应用一、实现TCP传输的客户端和服务端的简单互访

需求:客户端给服务端发送数据,服务端收到后,给客户端反馈信息。

客户端:

1,建立socket服务。指定要连接主机和端口。

2,获取socket流中的输出流。将数据写到该流中。通过网络发送给服务端。

3,获取socket流中的输入流,将服务端反馈的数据获取到,并打印。

4,关闭客户端资源。

关键在于通过getOutputStream()和getInputStream()获取读写流


view plain print ?
  1. package cn.xushuai.Test;  
  2. import java.io.*;  
  3. import java.net.*;  
  4.   
  5. class TcpClient2 {  
  6.     public static void main(String[] args)throws Exception {  
  7.         Socket s = new Socket("127.0.0.1",10007);  
  8.       
  9.         OutputStream out = s.getOutputStream();  
  10.         out.write("服务端,你好".getBytes());  
  11.   
  12.         InputStream in = s.getInputStream();  
  13.         byte[] buf = new byte[1024];  
  14.         int len = in.read(buf);  
  15.         System.out.println(new String(buf,0,len));  
  16.   
  17.         s.close();  
  18.     }  
  19. }  

服务端:

1,建立服务端的socket服务。ServerSocket();

       并监听一个端口。

2,获取连接过来的客户端对象。

       通过ServerSokcet的 accept方法。没有连接就会等,所以这个方法阻塞式的。

3,客户端如果发过来数据,那么服务端要使用对应的客户端对象,并获取到该客户端对象的读取流来读取发过来的数据。

       并打印在控制台。

4,关闭服务端。(可选)

view plain print ?
  1. class TcpServer2{  
  2.     public static void main(String[] args) throws Exception{  
  3.         ServerSocket ss = new ServerSocket(10007);  
  4.         Socket s = ss.accept();  
  5.   
  6.         String ip = s.getInetAddress().getHostAddress();  
  7.         System.out.println(ip+"....connected");  
  8.         InputStream in = s.getInputStream();  
  9.   
  10.         byte[] buf = new byte[1024];  
  11.         int len = in.read(buf);  
  12.         System.out.println(new String(buf,0,len));  
  13.         OutputStream out = s.getOutputStream();  
  14.   
  15.         //Thread.sleep(10000);  
  16.         out.write("哥们收到,你也好".getBytes());  
  17.         s.close();  
  18.         ss.close();  
  19.     }  
  20. }  

应用二、编写一个文本转换服务器

分析:

既然是操作设备上的数据,那么就可以使用io技术,并按照io的操作规律来思考。

都是文本数据,可以使用字符流进行操作,同时提高效率,加入缓冲。

客户端给服务端发送文本,服务单会将文本转成大写在返回给客户端。

而且客户度可以不断的进行文本转换。当客户端输入over时,转换结束。

 

该例子出现的问题:

现象:客户端和服务端都在莫名的等待。

原因:客户端和服务端都有阻塞式方法readLine(),这些方法没有读到结束标记,那么就一直等,而导致两端,都在等待。

 

为了书写简化,可以使用打印流,自动刷新与换行。


客户端:

源:键盘录入。  目的:网络设备,网络输出流。

而且操作的是文本数据,可以选择字符流。

 

步骤

1,建立服务。

2,获取键盘录入。

3,将数据发给服务端。

4,获取服务端返回的大写数据。

5,结束,关资源。

view plain print ?
  1. import java.io.*;  
  2. import java.net.*;  
  3.   
  4. class  TransClient{  
  5.     public static void main(String[] args) throws Exception{  
  6.         Socket s = new Socket("127.0.0.1",10010);  
  7.   
  8.         //定义读取键盘数据的流对象。  
  9.         BufferedReader bufr =   
  10.             new BufferedReader(new InputStreamReader(System.in));  
  11.   
  12.         //定义目的,将数据写入到socket输出流。发给服务端。  
  13.         //BufferedWriter bufOut =   
  14.             //new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));  
  15.         PrintWriter out = new PrintWriter(s.getOutputStream(),true);  
  16.   
  17.         //定义一个socket读取流,读取服务端返回的大写信息。  
  18.         BufferedReader bufIn =   
  19.             new BufferedReader(new InputStreamReader(s.getInputStream()));  
  20.   
  21.         String line = null;   
  22.         while((line=bufr.readLine())!=null){  
  23.             if("over".equals(line))  
  24.                 break;  
  25.               
  26.             out.println(line);  
  27.            //bufOut.write(line);        //将键盘录入写给服务端  
  28.            //bufOut.newLine();      //写入换行符,让服务端readLine识别,否则服务端一直阻塞  
  29.            //bufOut.flush();  
  30.   
  31.             String str =bufIn.readLine();   //读取服务端反馈的信息  
  32.             System.out.println("server:"+str);        
  33.         }  
  34.         bufr.close();  
  35.         s.close();  //会在socket流中加入结束标记,服务端会识别,所以在客户端结束//后,服务端也就结束了  
  36.     }  
  37. }</span>  


服务端:

源:socket读取流。目的:socket输出流。

都是文本,装饰。


view plain print ?
  1. class  TransServer{  
  2.     public static void main(String[] args) throws Exception{  
  3.         ServerSocket ss = new ServerSocket(10010);  
  4.   
  5.         Socket s = ss.accept();  
  6.         String ip = s.getInetAddress().getHostAddress();  
  7.         System.out.println(ip+"....connected");  
  8.   
  9.         //读取socket读取流中的数据。  
  10.         BufferedReader bufIn =  
  11.             new BufferedReader(new InputStreamReader(s.getInputStream()));  
  12.   
  13.         //目的:socket输出流,将大写数据写入到socket输出流,并发送给客户端。  
  14.         //BufferedWriter bufOut =   
  15.             //new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));  
  16.   
  17.         PrintWriter out = new PrintWriter(s.getOutputStream(),true);  
  18.   
  19.         String line = null;  
  20.         while((line=bufIn.readLine())!=null)//只有读到换行符才进行下次读取,否则一直阻塞{  
  21.   
  22.             System.out.println(line);  
  23.   
  24.             out.println(line.toUpperCase());  
  25.             //bufOut.write(line.toUpperCase());  
  26.             //bufOut.newLine();  //写入换行符,让客户端的readLine识别  
  27.             //bufOut.flush();        //必须刷新缓冲区  
  28.         }  
  29.   
  30.         s.close();  
  31.         ss.close();  
  32.   
  33.     }  
  34. }  

网络编程需注意的问题:


1、 读写流是否能读取到结束标记

读写流中的阻塞式方法read和write要刷新缓冲区和加入结束标记,readLine要进行换行操作,以便加入结束标记。

可以使用printReaader 和printWriter 来替代,有自动刷新和换行,这样简化了书写。


2、服务端是否能够接收到客户端结束标记

客户端上传完文件之后,需要向服务端提供一个结束标记。否则虽然客户端的循环结束,还会向下执行,又开始读取服务端反馈的信息,

但是,服务端还没有反馈时,客户端就向下执行了,以至于两端都阻塞。


3、自定义标签可能出现在文本中,所以导致文本文件还读取完就结束,所以使用通用的解决方案:shutDownOutput( )


服务端的服务线程:使用多线程实现并发访问,只需将共享的代码放在run方法中即可。

 


应用三、TCP上传文件

客户端:上传文本,并等待服务端的反馈信息

view plain print ?
  1. import java.io.*;  
  2. import java.net.*;  
  3.   
  4. //客户端上传文本,并等待服务端的反馈信息  
  5. class  TextClient{  
  6.     public static void main(String[] args) throws Exception{  
  7.         Socket s = new Socket("192.168.1.254",10006);  
  8.   
  9.         //生成一个缓冲读取流,同时关联一个文件  
  10.         BufferedReader bufr =   
  11.             new BufferedReader(new FileReader("IPDemo.java"));  
  12.   
  13.         //使用打印流,实现自动刷新和换行  
  14.         PrintWriter out = new PrintWriter(s.getOutputStream(),true);  
  15.   
  16.         //循环向服务端发送数据  
  17.         String line = null;  
  18.         while((line=bufr.readLine())!=null){  
  19.             out.println(line);  
  20.         }  
  21.           
  22.         //自定义结束标记  
  23.         //缺陷:文件中可能出现自定义标记符  
  24.         //out.println("over");  
  25.   
  26.         s.shutdownOutput();//关闭客户端的输出流,相当于,给流中加入一个结束标记-1.  
  27.         //服务端readLine()到-1时就结束读取,接着执行下面的代码  
  28.   
  29.         //得到一个缓冲读取流,用于获取服务端的反馈信息  
  30.         BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));  
  31.   
  32.         String str = bufIn.readLine();  
  33.         System.out.println(str);  
  34.   
  35.         bufr.close();  
  36.   
  37.         s.close();  
  38.     }  
  39. }  


服务端:收到上传的文件,保存到本地server.txt中,并反馈给客户端上传成功的信息
view plain print ?
  1. class  TextServer{  
  2.     public static void main(String[] args) throws Exception{  
  3.         ServerSocket ss = new ServerSocket(10006);  
  4.   
  5.         Socket s = ss.accept();  
  6.         String ip = s.getInetAddress().getHostAddress();  
  7.         System.out.println(ip+"....connected");  
  8.   
  9.         //得到一个缓冲读取流对象,用于读取客户端传过来的数据  
  10.         BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));  
  11.           
  12.         //得到一个打印流,用于写入读取的文件  
  13.         PrintWriter out  = new PrintWriter(new FileWriter("server.txt"),true);  
  14.   
  15.         String line = null;   
  16. //读取数据,直到读到结束标记  
  17.         while((line=bufIn.readLine())!=null){  
  18.             //if("over".equals(line))  
  19.                 //break;  
  20.             out.println(line);  
  21.         }  
  22.   
  23.         //获取一个写入流,向客户端反馈上传结果信息  
  24.         PrintWriter pw = new PrintWriter(s.getOutputStream(),true);  
  25.         pw.println("上传成功");  
  26.   
  27.         out.close();  
  28.         s.close();  
  29.         ss.close();  
  30.     }  
  31. }  


应用四、客户端并发上传图片

 

客户端

1,服务端点。

2,读取客户端已有的图片数据。

3,通过socket 输出流将数据发给服务端。

4,读取服务端反馈信息。

5,关闭。


view plain print ?
  1. import java.io.*;  
  2. import java.net.*;  
  3. class  PicClient{  
  4.     public static void main(String[] args)throws Exception {  
  5.         //只能传入一个文件名  
  6.         if(args.length!=1){  
  7.             System.out.println("请选择一个jpg格式的图片");  
  8.             return ;  
  9.         }  
  10.           
  11.         //验证文件是否存在并是一个文件  
  12.         File file = new File(args[0]);  
  13.         if(!(file.exists() && file.isFile())){  
  14.             System.out.println("该文件有问题,要么补存在,要么不是文件");  
  15.             return ;  
  16.         }  
  17.   
  18.         //限制图片为jpg格式  
  19.         if(!file.getName().endsWith(".jpg")){  
  20.             System.out.println("图片格式错误,请重新选择");  
  21.             return ;  
  22.         }     
  23.         //限定文件的大小  
  24.         if(file.length()>1024*1024*5){  
  25.             System.out.println("文件过大,没安好心");  
  26.             return ;  
  27.         }  
  28.   
  29.         Socket s = new Socket("192.168.1.254",10007);  
  30.         FileInputStream fis = new FileInputStream(file);  
  31.         OutputStream out = s.getOutputStream();  
  32.           
  33. byte[] buf = new byte[1024];  
  34.         int len = 0;  
  35.         while((len=fis.read(buf))!=-1){  
  36.             out.write(buf,0,len);  
  37.         }  
  38.   
  39.         //告诉服务端数据已写完  
  40.         s.shutdownOutput();  
  41.   
  42.         InputStream in = s.getInputStream();  
  43.         byte[] bufIn = new byte[1024];  
  44.         int num = in.read(bufIn);  
  45.         System.out.println(new String(bufIn,0,num));  
  46.   
  47.         fis.close();  
  48.         s.close();  
  49.     }  
  50. }  


服务端提供文件上传的线程代码:
view plain print ?
  1. class PicThread implements Runnable{  
  2.   
  3.     private Socket s;  
  4.     PicThread(Socket s){  
  5.         this.s = s;  
  6.     }  
  7.     public void run(){  
  8.   
  9.         int count = 1;//定义为局部变量,让每个客户都拥有一个变量,而不是共享(成员变量)  
  10.   
  11.         String ip  = s.getInetAddress().getHostAddress();  
  12.         try{  
  13.             System.out.println(ip+"....connected");  
  14.   
  15.             InputStream in = s.getInputStream();  
  16.   
  17.             File dir =  new File("d:\\pic");  
  18.   
  19.             File file = new File(dir,ip+"("+(count)+")"+".jpg");  
  20.   
  21.             //循环判断文件是否已经存在  
  22.             while(file.exists())  
  23.                 file = new File(dir,ip+"("+(count++)+")"+".jpg");  
  24.   
  25.             FileOutputStream fos = new FileOutputStream(file);  
  26.   
  27.             byte[] buf = new byte[1024];  
  28.   
  29.             int len = 0;  
  30.             while((len=in.read(buf))!=-1){  
  31.                 fos.write(buf,0,len);  
  32.             }  
  33.   
  34.             OutputStream out = s.getOutputStream();  
  35.   
  36.             out.write("上传成功".getBytes());  
  37.   
  38.             fos.close();  
  39.   
  40.             s.close();  
  41.         }  
  42.         catch (Exception e){  
  43.             throw new RuntimeException(ip+"上传失败");  
  44.         }  
  45.     }  
  46. }  

服务端:为每个要上传文件的客户new一个线程提供服务
view plain print ?
  1. class  PicServer{  
  2.     public static void main(String[] args) throws Exception{  
  3.         ServerSocket ss = new ServerSocket(10007);  
  4.   
  5.         while(true){  
  6.             Socket s = ss.accept();  
  7.   
  8.             new Thread(new PicThread(s)).start();     
  9.         }  
  10.         //ss.close();  
  11.     }  
  12. }  

应用五、登陆服务

需求:客户端向服务端发送用户请求登陆,服务端通过验证,返回”欢迎光临“,未通过”用户不存在“

客户端通过键盘录入用户名。

服务端对这个用户名进行校验。

  如果该用户存在,在服务端显示xxx,已登陆,并在客户端显示 xxx,欢迎光临。

如果该用户存在,在服务端显示xxx,尝试登陆,并在客户端显示 xxx,该用户不存在。

最多就登录三次。


客户端登陆代码:
view plain print ?
  1. import java.io.*;  
  2. import java.net.*;  
  3.   
  4. class  LoginClient{  
  5.     public static void main(String[] args) throws Exception{  
  6.         Socket s = new Socket("192.168.1.254",10008);  
  7.   
  8.         BufferedReader bufr =   
  9.             new BufferedReader(new InputStreamReader(System.in));  
  10.   
  11.         PrintWriter out = new PrintWriter(s.getOutputStream(),true);  
  12.   
  13.         BufferedReader bufIn =  
  14.             new BufferedReader(new InputStreamReader(s.getInputStream()));  
  15.   
  16.         for(int x=0; x<3; x++){  
  17.             String line = bufr.readLine();  
  18.             if(line==null)  
  19.                 break;  
  20.             out.println(line);  
  21.   
  22.             String info = bufIn.readLine();  
  23.             System.out.println("info:"+info);  
  24.             if(info.contains("欢迎"))  
  25.                 break;  
  26.         }  
  27.         bufr.close();  
  28.         s.close();  
  29.     }  
  30. }  


服务端提供登陆服务的线程

view plain print ?
  1. class UserThreadimplements Runnable{  
  2.          private Socket s;  
  3.          UserThread(Socket s){  
  4.                    this.s = s;  
  5.          }  
  6.          public void run(){  
  7.                    String ip =s.getInetAddress().getHostAddress();  
  8.                    System.out.println(ip+"....connected");  
  9.                    try{  
  10.                             for(int x=0; x<3;x++){  
  11.                                      BufferedReaderbufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));  
  12.                                      String name= bufIn.readLine();                   
  13.                                      //避免按Ctrl+C 结束时,readLine读取为null,不满足,而进行3次循环的判断,所以这里对null进行判断  
  14.                                      if(name==null)  
  15.                                                break;  
  16.    
  17.                                      BufferedReaderbufr = new BufferedReader(new FileReader("user.txt"));  
  18.                                      PrintWriterout = new PrintWriter(s.getOutputStream(),true);  
  19.                                      String line= null;  
  20.                                      booleanflag = false;          //定义标记,判断是否获取到用户  
  21.                                      while((line=bufr.readLine())!=null)     {//循环读取判断,用户是否存在     
  22.                                                if(line.equals(name)){  
  23.                                                         flag= true;  
  24.                                                         break;  
  25.                                                }                                    
  26.                                      }  
  27.                                       
  28.                                      if(flag){  
  29.                                                System.out.println(name+",已登录");  
  30.                                                out.println(name+",欢迎光临");  
  31.                                                break;  
  32.                                      }  
  33.                                      else{  
  34.                                                System.out.println(name+",尝试登录");  
  35.                                                out.println(name+",用户名不存在");  
  36.                                      }  
  37.                             }  
  38.                             s.close();  
  39.                    }  
  40.                    catch (Exception e){  
  41.                             throw newRuntimeException(ip+"校验失败");  
  42.                    }  
  43.          }  
  44. }  


服务端:不断循环以产生新的线程为客户端提供服务
view plain print ?
  1. class  LoginServer{  
  2.     public static void main(String[] args) throws Exception{  
  3.         ServerSocket ss = new ServerSocket(10008);  
  4.           
  5. //通过循环,不断提供服务  
  6.         while(true){  
  7.             Socket s = ss.accept();  
  8.             new Thread(new UserThread(s)).start();  
  9.         }  
  10.     }  
  11. }  

你可能感兴趣的:(Tcp传输应用)