> 文档中心 > TCP实战案例之即时通信、BS架构模拟

TCP实战案例之即时通信、BS架构模拟


即时通信是什么含义,要实现怎么样的设计?

1、即时通信,是指一个客户端消息发出去,其他客户端可以接收到

2、之前我们的消息都是发给服务端的

3、即时通信需要进行端口转发的设计思想

4、服务端需要把在线的Socket管道存储起来

5、一旦收到一个消息要推送给其他管道

客户端:

import java.io.*;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;import java.util.List;import java.util.Scanner;public class TCP_实战案例_即时通信 {    public static void main(String[] args) throws Exception { System.out.println("-----客户端启动-----"); //创建Socket通信管道请求与服务器的连接 /* public Socket(String host, int port) 参数一、服务器的IP地址 参数二、服务器的端口  */ Socket socket = new Socket("127.0.0.1", 7777); //创建一个独立的线程专门负责这个客户端的读消息(服务端随时可能转发!) new ClientReaderThread(socket).start(); //从Socket通信管道中得到一个字节输出流,负责发送数据 OutputStream out = socket.getOutputStream(); //把低级的字节流包装成打印流 PrintStream ps = new PrintStream(out); Scanner sc = new Scanner(System.in); while (true) {     System.out.println("请输入你要发送的消息:");     String line = sc.nextLine();     //发送消息     ps.println(line);     //刷新     ps.flush(); }    }}//客户端读消息线程class ClientReaderThread extends Thread{    private Socket socket;    public ClientReaderThread(Socket socket) { this.socket = socket;    }    @Override    public void run() { try {     //从Socket通信管道中得到一个字节输入流     InputStream is = socket.getInputStream();     //把字节输入流包装成缓冲字节输入流进行消息的接收     BufferedReader br = new BufferedReader(new InputStreamReader(is));     //按照行读取消息     String line;     while ((line = br.readLine()) != null) {  System.out.println("收到消息:" + line);     } } catch (Exception e) {     System.out.println( "服务端已把你踢出!"); }    }}

 服务端:

import java.io.*;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;import java.util.List;import java.util.Scanner;class TCP_即时通信_服务端 {    //定义一个静态的List集合存储当前全部在线的socket管道    public static List allonlineSockets=new ArrayList();    public static void main(String[] args) throws Exception { System.out.println("-----服务端启动-----"); //注册端口 ServerSocket serverSocket = new ServerSocket(7777); //定义一个死循环由主线程负责不断的接收客户端的Socket通信管道连接 while (true) {     //每接收一个客户端的Socket通信管道,交给一个独立的子线程负责读取信息     Socket socket = serverSocket.accept();     System.out.println(socket.getRemoteSocketAddress() + "上线了");     allonlineSockets.add(socket);//上线完成     //创建一个独立的线程单独处理这个socket管道     new ServerReaderThread(socket).start(); }    }}class ServerReaderThread extends Thread {    private Socket socket;    public ServerReaderThread(Socket socket) { this.socket = socket;    }    @Override    public void run() { try {     //从Socket通信管道中得到一个字节输入流     InputStream is = socket.getInputStream();     //把字节输入流包装成缓冲字节输入流进行消息的接收     BufferedReader br = new BufferedReader(new InputStreamReader(is));     //按照行读取消息     String line;     while ((line = br.readLine()) != null) {  System.out.println("收到了消息:" + line);  //把这个消息进行端口转发给全部客户端socket管道  sendMsgToAll(line);     } } catch (Exception e) {     System.out.println(socket.getRemoteSocketAddress() + "下线了");     TCP_即时通信_服务端.allonlineSockets.remove(socket);//删除 }    }//独立功能独立成方法    private void sendMsgToAll(String msg) throws Exception { for (Socket socket : TCP_即时通信_服务端.allonlineSockets) {     PrintStream ps=new PrintStream(socket.getOutputStream());     ps.println(msg);     ps.flush(); }    }}

运行效果: 

 

 

 这里有个缺陷就是发的消息没有屏蔽自己,两个一样的是因为开了并发。

下面是服务端关闭后的效果:

 

 

 BS架构模拟:

1、之前的客户端都是什么样的?

其实就是CS架构,客户端是需要我们自己开发实现的。

2、BS结构是什么样的,需要开发客户端吗?

 浏览器访问服务端,不需要开发客户端。

简单模拟: 

import java.io.*;import java.net.ServerSocket;import java.net.Socket;import java.util.concurrent.*;public class TCP_BS架构 {    public static void main(String[] args) throws Exception { //注册端口 ServerSocket serverSocket = new ServerSocket(7070); //定义一个死循环由主线程负责不断的接收客户端的Socket通信管道连接 while (true) {     //每接收一个客户端的Socket通信管道,交给一个独立的子线程负责读取信息     Socket socket = serverSocket.accept();     //创建一个独立的线程单独处理这个socket管道     new ServerReaderThread2(socket).start(); }    }}class ServerReaderThread2 extends Thread {    private Socket socket;    public ServerReaderThread2(Socket socket) { this.socket = socket;    }    @Override    public void run() { //浏览器已经与本线程建立socket管道 //响应消息给浏览器显示 try {     PrintStream ps=new PrintStream(socket.getOutputStream());     //必须响应HTTP协议格式数据,否则浏览器不认识消息     ps.println("HTTP/1.1 200 OK");//协议类型和版本 响应成功的消息     ps.println("Content-Type:text/html;charset=UTF-8");//响应的数据类型:文本/网页     ps.println();//必须发送一个空格     //才可以响应数据回去给浏览器     ps.println("《遇安.》 ");     ps.close(); } catch (Exception e) {     e.printStackTrace(); }    }}

 线程池优化:

import java.io.*;import java.net.ServerSocket;import java.net.Socket;import java.util.concurrent.*;public class TCP_BS架构 {    private static ExecutorService pools = new ThreadPoolExecutor(3, 5,     6, TimeUnit.SECONDS, new ArrayBlockingQueue(3),     Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());    public static void main(String[] args) throws Exception { //注册端口 ServerSocket serverSocket = new ServerSocket(7070); //定义一个死循环由主线程负责不断的接收客户端的Socket通信管道连接 while (true) {     //每接收一个客户端的Socket通信管道,交给一个独立的子线程负责读取信息     Socket socket = serverSocket.accept();    pools.execute(new ServerRunnable2(socket)); }    }}class ServerRunnable2 implements Runnable {    private Socket socket;    public ServerRunnable2(Socket socket) { this.socket = socket;    }    @Override    public void run() { //浏览器已经与本线程建立socket管道 //响应消息给浏览器显示 try {     PrintStream ps=new PrintStream(socket.getOutputStream());     //必须响应HTTP协议格式数据,否则浏览器不认识消息     ps.println("HTTP/1.1 200 OK");//协议类型和版本 响应成功的消息     ps.println("Content-Type:text/html;charset=UTF-8");//响应的数据类型:文本/网页     ps.println();//必须发送一个空格     //才可以响应数据回去给浏览器     ps.println("《遇安.》 ");     ps.close(); } catch (Exception e) {     System.out.println(socket.getRemoteSocketAddress() + "下线了"); }    }}

 在浏览器的效果图:

开发者涨薪指南 TCP实战案例之即时通信、BS架构模拟 48位大咖的思考法则、工作方式、逻辑体系