天天看點

TCP一對多聊天伺服器的實作(多線程場景)

1.伺服器的連接配接設計

TCP一對多聊天伺服器的實作(多線程場景)

2.伺服器的線程設計

3.建立服務端

package com.yqq.app3;

/**
 * @Author yqq
 * @Date 2021/11/08 22:28
 * @Version 1.0
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 接受用戶端發送消息的線程
 */
class ChatReceive extends Thread{
    private Socket socket;
    public ChatReceive(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        this.receiveMsg();
    }
    /**
     * 實作接受用戶端發送的消息
     */
    private void receiveMsg(){
        BufferedReader br =null;
        try {
            br=new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
            while(true){
                String msg = br.readLine();
                //将資料加入資料公共區域
                synchronized ("yqq"){
                    ChatRoomServer.buf="["+this.socket.getInetAddress()+"]"+msg;
                    //喚醒等待的線程,被相同鎖對象使用者
                    "yqq".notifyAll();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(br!=null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(this.socket!=null){
                try {
                    this.socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
/**
 * 向用戶端發送消息的線程
 */
class ChatSend extends Thread{
    Socket socket=null;
    public ChatSend(Socket socket){
        this.socket=socket;
    }
    @Override
    public void run() {
        this.sendMsg();
    }
    /**
     * 将公共資料區域的資料發送給用戶端
     */
    private void sendMsg(){
        PrintWriter pw =null;
        try {
            pw =new PrintWriter(this.socket.getOutputStream());
            while (true){
                synchronized ("yqq"){
                    //讓發送消息的線程處于等待狀态
                    "yqq".wait();
                    //将公共資料區中的消息發送給用戶端
                    pw.println(ChatRoomServer.buf);
                    pw.flush();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(pw!=null){
                pw.close();
            }
            if(this.socket!=null){
                try {
                    this.socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
public class ChatRoomServer {
    //定義公共資料區
    public static String buf;
    public static void main(String[] args) {
        System.out.println("Chat Server Version 1.0");
        System.out.println("Listen at 8888");
        ServerSocket serverSocket =null;
        try {
            serverSocket=new ServerSocket(8888);
            while (true){
                Socket socket=serverSocket.accept();
                System.out.println("連接配接到:"+socket.getInetAddress());
                new ChatReceive(socket).start();
                new ChatSend(socket).start();
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(serverSocket!=null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}      

4.建立用戶端

package com.yqq.app3;

/**
 * @Author yqq
 * @Date 2021/11/08 22:28
 * @Version 1.0
 */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

/**
 * 發送消息線程
 */
class Send1 extends Thread{
    private Socket socket;
    private Scanner scanner;
    public Send1(Socket socket,Scanner scanner){
        this.socket = socket;
        this.scanner = scanner;
    }
    @Override
    public void run() {
        this.sendMsg();
    }
    /**
     * 發送消息
     */
    private void sendMsg(){

        PrintWriter pw = null;
        try{
            //建立向對方輸出消息的流對象
            pw = new PrintWriter(this.socket.getOutputStream());
            while(true){
                String msg = scanner.nextLine();
                pw.println(msg);
                pw.flush();
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            if(scanner != null ){
                scanner.close();
            }
            if(pw != null){
                pw.close();
            }
            if(this.socket != null){
                try {
                    this.socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

/**
 * 接收消息的線程
 */
class Receive1 extends Thread{
    private Socket socket;
    public Receive1(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        this.receiveMsg();
    }
    /**
     * 用于接收對方消息的方法
     */
    private void receiveMsg(){
        BufferedReader br = null;
        try{
            //建立用于接收對方發送消息的流對象
            br = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
            while(true){
                String msg = br.readLine();
                System.out.println("他說:"+msg);
            }
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(br != null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(this.socket != null){
                try {
                    this.socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
public class GoodTCP {
    public static void main(String[] args) {
        Scanner scanner = null;
        ServerSocket serverSocket = null;
        Socket socket = null;
        try{
            scanner = new Scanner(System.in);
            System.out.println("請輸入:server,<port> 或者:<ip>,<port>");
            String str = scanner.nextLine();
            String[] arr = str.split(",");
            if("server".equals(arr[0])){
                //啟動服務端
                System.out.println("TCP Server Listen at "+arr[1]+" .....");
                serverSocket = new ServerSocket(Integer.parseInt(arr[1]));
                socket = serverSocket.accept();
                System.out.println("連接配接成功!");

            }else{
                //啟動用戶端
               socket = new Socket(arr[0],Integer.parseInt(arr[1]));
                System.out.println("連接配接成功!");
            }
            //啟動發送消息的線程
            new Send1(socket,scanner).start();
            //啟動接收消息的線程
            new Receive1(socket).start();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(serverSocket != null){
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}      

5.通信