QQ聊天室案例
服务器分析
第一:服务器要连接的不是一个客户端,那么如何解决这个问题?
解决这个问题就需要服务器分别为每个连接的客户端都创建一个服务器,就需要服务器多开,也就是服务器要开多个线程,每个线程分别对应一个客户端。
第二:我们要解决的是服务器的监听问题。
服务器的流程是监听客户端信息,然后发送客户端信息,但是如果说此时此刻另一个客户端发送了信息,但是此时的服务器正在处理另一个客户端的信息,此时他并不处于监听状态,那么另一个客户端的信息他就无法处理。
我们只需要让监听程序一直循环,处于一直监听的状态,同时让服务器的监听和处理数据处于两个不同的线程。
第三:然后针对数据的输出问题
服务器发送信息是应该改将信息发送到所有客户端,这时候只需要将所有客户端放入集合中,然后一次性遍历所有客户端。这样就实现了将信息发到所有的客户端。
服务器的线程的代码
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import java.util.Vector; public class SeverThread extends Thread { private Socket socket; private Vector<Socket> sockets; public SeverThread(Socket socket, Vector<Socket> sockets){ this.socket = socket; this.sockets = sockets; } @Override public void run() { String ip = socket.getInetAddress().getHostAddress(); System.out.println(ip+"连接了!"); //获得输入流 try { BufferedReader br = new BufferedReader(new InputStreamReader( socket.getInputStream())) ; String msg = ""; while((msg = br.readLine()) != null){ sendToAll(ip+":"+msg); } //String ip = socket.getInetAddress().getHostAddress(); } catch (IOException e) { //e.printStackTrace(); sockets.remove(socket); } } public void sendToAll(String msg) { try { for (Socket socket : sockets) { PrintStream ps = new PrintStream(socket.getOutputStream()); ps.println(msg); ps.flush(); } } catch (IOException e) { e.printStackTrace(); } } }
服务器的代码
import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.util.Vector; public class Sever { public static void main(String[] args) throws IOException { System.out.println("--------开启QQ聊天室的服务器-----------"); ServerSocket serverSocket = new ServerSocket(8888); Vector<Socket> sockets = new Vector<>(); //侦听客户端的行为 while(true){ //获得连接的Socket对象 //main -> 负责持续侦听 Socket socket = serverSocket.accept(); sockets.add(socket); //创建线程 //th线程负责 信息转发 SeverThread th = new SeverThread(socket,sockets); th.start(); } } }
客户端分析
客户端的接受和输入的问题
QQ聊天的时候,我们发送信息和接送信息是不会互相影响的,因此,在做客户端的时候我们应该将输入线程和输出线程分开。我们在发送信息和接收信息是,往往是接受多条或者发送多条信息,因此我们需要让客户端一直处于输入或者输出的状态。
输入线程的代码
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; public class ReciveThread extends Thread { private Socket socket; public ReciveThread(Socket socket) { this.socket=socket; } @Override public void run() { try { while (true) { BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String msg = null; while ((msg=br.readLine())!=null) { System.out.println(msg); } } } catch (IOException e) { e.printStackTrace(); } } }
输出线程的代码
import java.io.IOException; import java.io.PrintStream; import java.net.Socket; import java.util.Scanner; public class SendThread extends Thread { private Socket socket; public SendThread(Socket socket){ this.socket=socket; } @Override public void run() { while (true){ try { PrintStream printStream=new PrintStream(socket.getOutputStream()); Scanner sc=new Scanner(System.in); String mag=sc.nextLine(); printStream.println(mag); printStream.flush(); } catch (IOException e) { e.printStackTrace(); } } } }
客户端的代码
import java.io.IOException; import java.net.Socket; public class QQClient { public static void main(String[] args) throws IOException { System.out.println("-----欢迎进入QQ聊天室-----"); Socket socket=new Socket("192.168.31.213",8888); //创建收发信息线程 ReciveThread th=new ReciveThread(socket); th.start(); SendThread th1=new SendThread(socket); th1.start(); } }