最近在复习java io相关知识 ,发现很多细节之前没学习到位,原理也没吃透,只能感叹本人愚钝。
复习到bio,顺手写了个简单的聊天室功能,并和大家分享下。
服务端:
package io.QQ聊天室实现_BIO; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List; public class ChartServer { public static void main (String[] args) throws IOException { ChartServer server = new ChartServer(); server.init(8889).listener(); } private ServerSocket serverSocket; private final List<ProcessorThread> clients = new ArrayList<>(); public ChartServer init(int port) throws IOException { this.serverSocket =new ServerSocket(port); return this; } public void listener() throws IOException { //主线程负责监听,启动监听线程 System.out.println("listener start"); new Thread(new AcceptThread(serverSocket)).start(); } class AcceptThread implements Runnable{ private ServerSocket serverSocket; public AcceptThread (ServerSocket serverSocket) { this.serverSocket = serverSocket; } @Override public void run () { while (true){ try { Socket socket = serverSocket.accept(); //子线程负责分发任务 new Thread(new ProcessorThread(socket)).start(); } catch (IOException e) { e.printStackTrace(); } } } } class ProcessorThread implements Runnable{ Socket socket; public ProcessorThread (Socket socket) { this.socket = socket; } @Override public void run () { String key = "["+socket.getInetAddress().getHostAddress()+":"+socket.getPort()+"]"; System.out.println(key+"上线了"); try { writeMsg(socket,key+"上线了"); clients.add(this); readMsg(socket,key); } catch (IOException e) { e.printStackTrace(); } } public String readMsg(Socket socket,String name) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String readLine; while (true){ readLine = br.readLine(); System.out.println(name+"说:"+readLine); writeMsg(socket,name+"说:"+readLine); } } public void writeMsg(Socket socket,String msg) throws IOException { //轮询 OutputStream os; for(ProcessorThread s:clients){ os = s.socket.getOutputStream(); os.write(msg.getBytes()); os.write(" ".getBytes()); os.flush(); } } } }
客户端:
package io.QQ聊天室实现_BIO; import java.io.*; import java.net.Socket; import java.util.Scanner; public class ChartClient { private Socket socket; public void init(String host,int port) throws IOException { Scanner scanner = new Scanner(System.in); socket = new Socket(host,port); new Thread(new readThread(socket)).start(); while (scanner.hasNextLine()){ String inputStr = scanner.nextLine(); OutputStream os = socket.getOutputStream(); OutputStreamWriter osw = new OutputStreamWriter(os,"UTF-8"); osw.write(inputStr); osw.write(" "); osw.flush(); } } class readThread implements Runnable{ Socket socket; InputStream answer ; public readThread (Socket socket) throws IOException { this.socket = socket; answer = socket.getInputStream(); } @Override public void run () { while (true){ BufferedReader br = new BufferedReader(new InputStreamReader(answer)); try { StringBuffer sb = new StringBuffer(); String readLine; while (true){ readLine = br.readLine(); sb.append(readLine); System.out.println(readLine); } } catch (IOException e) { e.printStackTrace(); } } } } static String host = "127.0.0.1"; static int port = 8889; public static void main (String[] args) throws IOException { ChartClient chartClient = new ChartClient(); chartClient.init(host,port); } }
总结:
在本例中,最重要的是要理解socket.accept()方法是阻塞的。bio中提供的流写入读取是阻塞的,如inputStream.read 是阻塞的。BufferedReader.readline()的结束标志。
在java网络编程或者java多线程编程中,线程分工是很重要的思想,可以参照tomcat等成熟容器的设计学习。