一、思路简介0 j0 J* J% a6 @
分为客户端和服务器两个类,所有的客户端将聊的内容发送给服务器,服务器接受后,将每一条内容发送给每一个客户端,客户端再显示在终端上。
' O# i% d f1 L# }" p二、客户端设计0 ^% v* {" E% N& b, F8 s
客户端包含2个线程,1个用来接受服务器的信息,再显示,1个用来接收键盘的输入,发送给服务器。
9 o2 Y: Q m. |* a
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.Socket;
- import java.nio.charset.StandardCharsets;
- import java.util.Scanner;
-
- public class WeChatClient { //WeChat的客户端类
- private Socket client;
- private String name;
- private InputStream in;
- private OutputStream out;
- private MassageSenter massageSenter;
- private MassageGeter massageGeter;
- class MassageGeter extends Thread{ //一个子线程类,用于客户端接收消息
- MassageGeter() throws IOException{
- in = client.getInputStream();
- }
- @Override
- public void run() {
- int len;
- byte[] bytes = new byte[1024];
- try {
- while ((len = in.read(bytes)) != -1) { //此函数是阻塞的
- System.out.println(new String(bytes,0,len, StandardCharsets.UTF_8));
- }
- }catch (IOException e){
- System.out.println(e.toString());
- }
- System.out.println("Connection interruption");
- }
- }
- class MassageSenter extends Thread{ //一个子线程类,用于发送消息给服务器
- MassageSenter() throws IOException{
- out = client.getOutputStream();
- }
-
- @Override
- public void run() {
- Scanner scanner = new Scanner(System.in);
- try {
- while (scanner.hasNextLine()) { //此函数为阻塞的函数
- String massage = scanner.nextLine();
- out.write((name + " : " + massage).getBytes(StandardCharsets.UTF_8));
- if(massage.equals("//exit"))
- break;
- }
- }catch (IOException e){
- e.printStackTrace();
- }
- }
- }
-
- WeChatClient(String name, String host, int port) throws IOException {//初始化,实例化发送和接收2个线程
- this.name = name;
- client = new Socket(host,port);
- massageGeter = new MassageGeter();
- massageSenter = new MassageSenter();
-
- }
-
- void login() throws IOException{//登录时,先发送名字给服务器,在接收到服务器的正确回应之后,启动线程
- out.write(name.getBytes(StandardCharsets.UTF_8));
- byte[] bytes = new byte[1024];
- int len;
- len = in.read(bytes);
- String answer = new String(bytes,0,len, StandardCharsets.UTF_8);
- if(answer.equals("logined!")) {
- System.out.println("Welcome to WeChat! "+name);
- massageSenter.start();
- massageGeter.start();
- try {
- massageSenter.join();//join()的作用是等线程结束之后再继续执行主线程(main)
- massageGeter.join();
- }catch (InterruptedException e){
- System.err.println(e.toString());
- }
-
- }else{
- System.out.println("Server Wrong");
- }
- client.close();
- }
-
-
- public static void main(String[] args) throws IOException{//程序入口
- String host = "127.0.0.1";
- WeChatClient client = new WeChatClient("Uzi",host,7777);
- client.login();
- }
-
- }
三、服务器设计. m0 g9 b6 }6 t7 D
服务器包含3个线程类,端口监听线程,客户端接收信息线程,发送信息线程。服务器类还包含并维护着一个已经连接的用户列表,和一个待发送信息列表。6 I }* m' c% d/ _+ o) ]
服务器有一个负责监听端口的线程,此线程在接收到客户端的连接请求后,将连接的客户端添加进用户列表;并为每一个连接的客户端实例化一个接受信息的线程类,从各个客户端接收员信息,并存入待发送信息列表。发送信息线程查看列表是否为空,若不为空,则将里面的信息发送给用户列表的每一个用户。) [5 C2 e2 ?3 L
|