1.如上图 在服务器与客户端进行通信的过程中 主要进行数据包的传递,
1)对于客户端与客户端之间 应该是互不影响有独立管道,Java模拟过程中 使用多线程的方法对其进行处理,多个线程拥有各自的读写数据的功能
2)对于服务器端 相当于中转站,对于来自于不同的客户端的消息请求 应该要分别进行处理,所以服务器端需要使用多线程方法(l来一个客户端就必须开启一个新的线程)同样共享 读写操作;2.
2. 编程理解:
1) 客户端拥有各自的 send ,receive数据的功能,因此在编程中将 send 与 receive方法进行封装
对于 send方法编程:
1 package recover; 2 3 import java.io.*; 4 import java.net.Socket; 5 6 import Cheat.CloseUtil; 7 8 public class ClientSend implements Runnable{ 9 10 /**DataInputStream : 从 控制台得到消息 11 * DataOutputStream: 将数据进行发送*/ 12 private DataOutputStream dos; 13 private BufferedReader dis; 14 15 private String name; 16 boolean isRunnable=true; 17 public ClientSend() 18 { 19 dis=new BufferedReader(new InputStreamReader(System.in)); 20 } 21 // 从控制台得到消息 22 private String getMsgFromConsule() { 23 // TODO Auto-generated method stub 24 try { 25 return dis.readLine(); 26 } catch (IOException e) { 27 // TODO Auto-generated catch block 28 e.printStackTrace(); 29 } 30 return null; 31 } 32 public ClientSend(Socket client,String name) 33 { 34 try { 35 // 从客户端进行输出 36 this.dos=new DataOutputStream(client.getOutputStream()); 37 this.name=name; 38 } catch (IOException e) { 39 // TODO Auto-generated catch block 40 //e.printStackTrace(); 41 isRunnable=true; 42 try { 43 CloseUtil.closeAll(dos,dis); 44 } catch (IOException e1) { 45 // TODO Auto-generated catch block 46 e1.printStackTrace(); 47 } 48 } 49 50 } 51 52 public void send(String msg) 53 { 54 if(null!=msg && !msg.equals("")) 55 { 56 try { 57 dos.writeUTF(msg); 58 dos.flush(); 59 } catch (IOException e) { 60 // TODO Auto-generated catch block 61 e.printStackTrace(); 62 } 63 } 64 } 65 @Override 66 public void run() { 67 // TODO Auto-generated method stub 68 while(isRunnable) 69 send( getMsgFromConsule()); 70 } 71 72 73 }
在client 中通过调用线程方式:
1 import java.io.BufferedReader; 2 import java.io.IOException; 3 import java.io.InputStreamReader; 4 import java.net.Socket; 5 import java.net.UnknownHostException; 6 7 public class client2 { 8 /**使用多线程概念 9 * @throws IOException 10 * @throws UnknownHostException */ 11 public static void main(String[] args) throws UnknownHostException, IOException { 12 // TODO Auto-generated method stub 13 14 // 建立私聊 必须从 控制台的得到pc 名称 15 System.out.println("进入到客户端"); 16 17 BufferedReader info=new BufferedReader(new InputStreamReader(System.in)); 18 String name=null; 19 if((name=info.readLine())==null) 20 return; 21 22 /************************使用多线程 --之上代码 输入名字理解**************************************/ 23 Socket client1=new Socket("localhost",9999); 24 25 // 发送数据 26 new Thread(new Send(client1,name)).start(); 27 new Thread(new Reader(client1)).start(); 28 } 29 30 }
2). 同理对于服务器端 首先 对 读写操作 进行封装,主要是为了每一个 客户端预录 独立管道:
注意:sendf方法 服务器将接收到的消息返回发送
sendother:通过广播的方法将接受到消息发送其他人
1 private class MyChanner implements Runnable{ 2 private DataInputStream dis; 3 private DataOutputStream dos; 4 private String name; 5 boolean isRunnable=true; 6 7 public MyChanner(Socket client) throws IOException 8 { 9 try { 10 this.dis=new DataInputStream(client.getInputStream()); 11 12 this.dos=new DataOutputStream(client.getOutputStream()); 13 this.name=dis.readUTF(); 14 this.send("欢迎您"+"进入到聊天室"); 15 this.sendother(this.name+"进入聊天室"); 16 } catch (IOException e) { 17 // TODO Auto-generated catch block 18 //e.printStackTrace(); 19 CloseUtil.closeAll(dis,dos); 20 isRunnable=false; 21 } 22 23 } 24 25 private String receive() throws IOException 26 { 27 String msg=""; 28 try { 29 msg= dis.readUTF(); 30 } catch (IOException e) { 31 // TODO Auto-generated catch block 32 //e.printStackTrace(); 33 CloseUtil.closeAll(dis); 34 isRunnable=false; 35 all.remove(this); 36 } 37 return msg; 38 39 } 40 41 private void send(String msg) throws IOException 42 { 43 if (msg==null || msg=="") 44 return; 45 46 try { 47 dos.writeUTF(msg); 48 dos.flush(); 49 } catch (IOException e) { 50 // TODO Auto-generated catch block 51 //e.printStackTrace(); 52 CloseUtil.closeAll(dos); 53 isRunnable=false; 54 all.remove(this); 55 } 56 57 } 58 private void sendother(String msg) throws IOException 59 { 60 // String msg=receive(); 61 //遍历容器 62 for(MyChanner temp:all) 63 { 64 if(temp==this) 65 continue; 66 //发送其他客户端 67 temp.send(msg); 68 } 69 } 70 71 @Override 72 public void run() { 73 // TODO Auto-generated method stub 74 while(isRunnable) 75 { 76 try { 77 sendother(receive());//明显自己发给自己 78 } catch (IOException e) { 79 // TODO Auto-generated catch block 80 e.printStackTrace(); 81 } 82 83 84 } 85 } 86 87 }
为了将 消息发送给其他客户端,使用 容器将所有的客户端都加入到容器中,通过关键字---客户主机之间映射,将消息发送给指定 客户端完成私聊的作用;
2)通过 while循环 让服务器一直处在于不断地监听信息的状态,
1 // 做成广播形式 2 public void start() throws IOException 3 { 4 ServerSocket server=new ServerSocket(9999); 5 6 while(true) 7 { 8 Socket socket=server.accept(); 9 10 MyChanner channer1=new MyChanner(socket); 11 all.add(channer1);//加入容器中同一管理 12 new Thread(channer1).start(); 13 } 14 }
整体程序:
1 package Cheat; 2 3 import java.io.DataInputStream; 4 import java.io.DataOutputStream; 5 import java.io.IOException; 6 import java.net.ServerSocket; 7 import java.net.Socket; 8 import java.util.ArrayList; 9 import java.util.List; 10 11 /**1. 服务器保持独立,客户端进行服务器,每个客户端应该互不影响 12 * 2. 对服务器进行多线程处理 13 * 14 * 3. 将输入流与输出流进行封装*/ 15 public class Server1 { 16 17 public static void main(String[] args) throws IOException { 18 // TODO Auto-generated method stub 19 new Server1().start(); 20 21 } 22 // 做一个容器,将所有线程键入其中 23 private List<MyChanner> all=new ArrayList<MyChanner>(); 24 25 // 做成广播形式 26 public void start() throws IOException 27 { 28 ServerSocket server=new ServerSocket(9999); 29 30 while(true) 31 { 32 Socket socket=server.accept(); 33 34 MyChanner channer1=new MyChanner(socket); 35 all.add(channer1);//加入容器中同一管理 36 new Thread(channer1).start(); 37 } 38 } 39 40 private class MyChanner implements Runnable{ 41 private DataInputStream dis; 42 private DataOutputStream dos; 43 private String name; 44 boolean isRunnable=true; 45 46 public MyChanner(Socket client) throws IOException 47 { 48 try { 49 this.dis=new DataInputStream(client.getInputStream()); 50 51 this.dos=new DataOutputStream(client.getOutputStream()); 52 this.name=dis.readUTF(); 53 this.send("欢迎您"+"进入到聊天室"); 54 this.sendother(this.name+"进入聊天室"); 55 } catch (IOException e) { 56 // TODO Auto-generated catch block 57 //e.printStackTrace(); 58 CloseUtil.closeAll(dis,dos); 59 isRunnable=false; 60 } 61 62 } 63 64 private String receive() throws IOException 65 { 66 String msg=""; 67 try { 68 msg= dis.readUTF(); 69 } catch (IOException e) { 70 // TODO Auto-generated catch block 71 //e.printStackTrace(); 72 CloseUtil.closeAll(dis); 73 isRunnable=false; 74 all.remove(this); 75 } 76 return msg; 77 78 } 79 80 private void send(String msg) throws IOException 81 { 82 if (msg==null || msg=="") 83 return; 84 85 try { 86 dos.writeUTF(msg); 87 dos.flush(); 88 } catch (IOException e) { 89 // TODO Auto-generated catch block 90 //e.printStackTrace(); 91 CloseUtil.closeAll(dos); 92 isRunnable=false; 93 all.remove(this); 94 } 95 96 } 97 private void sendother(String msg) throws IOException 98 { 99 // String msg=receive(); 100 //遍历容器 101 for(MyChanner temp:all) 102 { 103 if(temp==this) 104 continue; 105 //发送其他客户端 106 temp.send(msg); 107 } 108 } 109 110 @Override 111 public void run() { 112 // TODO Auto-generated method stub 113 while(isRunnable) 114 { 115 try { 116 sendother(receive());//明显自己发给自己 117 } catch (IOException e) { 118 // TODO Auto-generated catch block 119 e.printStackTrace(); 120 } 121 122 123 } 124 } 125 126 } 127 }