Contact me:

JAVA 无图形界面 单线程聊天程序

起因

想用JAVA做一个聊天室程序,学了TCP里Socket和ServerSocket,就蠢蠢欲动,写了一个只能回复一条才能看到收到的简单程序。

知识点。

客户端

Socket client = new Socket("localhost",8888) ; // 客户端连服务器
BufferedReader buf = new BufferedReader(new InputStreamReader(client.getInputStream())) ; // 输入流,之后用于读取
PrintStream out = new PrintStream(client.getOutputStream()) ; // 输出流,发送数据

服务器

ServerSocket ss=new ServerSocket(8888);
Socket byclient = ss.accept() ; // 这个client是服务器到客户端的socket; 注意后面IO流!!!得到连接,程序进入到阻塞状态
out = new PrintStream(byclient.getOutputStream()) ; //输出流
BufferedReader buf = new BufferedReader(new InputStreamReader(byclient.getInputStream())) ;// 输入流 !!!注意对比!准备接收客户端的输入信息

问题

想了很久都没法实现正常的聊天功能,要么只能接一条发一条就结束,要么就只能一直接。。。
然后查了一下,发现需要用多线程的知识来解决这个问题

代码

我的简单聊天

服务器端

import java.io.*;
import java.net.*;
public class SERV {
    Socket cl;
    ServerSocket ser;

    public SERV() throws IOException {
        this.ser = new ServerSocket(9999);
        InetAddress inetAddr = InetAddress.getLocalHost();
        System.out.println("Connecting,LocalIP:"+ inetAddr.getHostAddress());
        this.cl = ser.accept();
        //System.out.println("Connected");
        PrintStream ot=new PrintStream(cl.getOutputStream());
        BufferedReader rd=new BufferedReader(new InputStreamReader(System.in));
        BufferedReader in= new BufferedReader(new InputStreamReader(cl.getInputStream()));
        ot.println("plz");

        while (true){
            System.out.println();
                System.out.print("Client:");
                String clt=in.readLine();
                System.out.println(clt);
                System.out.print("Message:");
                String out = rd.readLine();
                ot.println(out);
        }

    }
    public static void main(String[] args) throws IOException {
        SERV SERV=new SERV();

    }
}

客户端

import java.io.*;
import java.net.*;

public class CL {
    Socket cl;
    public CL(String ip) throws IOException {
        this.cl=new Socket(ip,9999);
        System.out.println("OK");
        BufferedReader in= new BufferedReader(new InputStreamReader(cl.getInputStream()));
        BufferedReader rd=new BufferedReader(new InputStreamReader(System.in));
        PrintStream ot=new PrintStream(cl.getOutputStream(),true);
        ot.println("connected");

        while (true) {
                System.out.print("Server:");
                String sv = in.readLine();
                System.out.println(sv);
                System.out.println("Message:");
                String msg = rd.readLine();
                ot.println(msg);
        }
    }
    public static void main(String[] args) throws IOException {
        System.out.println("enter your dest-ip:");
        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
        String ip= br.readLine();
        CL CL=new CL(ip);
    }
}


多线程

客户端:

import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
//读线程
class ReadFromServer implements Runnable{
    private Socket client;
    public ReadFromServer(Socket client) {
        this.client = client;
    }
    @Override
    public void run() {
        try {
            //获取输入流来取得服务器发来的信息
            Scanner in = new Scanner(client.getInputStream());
            while (true){
                if (client.isClosed()){
                    System.out.println("客户端已经关闭");
                    in.close();
                    break;
                }
                if(in.hasNext()){
                    String msgFromServer = in.nextLine();
                    System.out.println("服务器发来的信息为:"+msgFromServer);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

//写线程
class SendMsgToServer implements Runnable{
    private Socket client;
    public SendMsgToServer(Socket client) {
        this.client = client;
    }
    @Override
    public void run() {
        try {
            PrintStream out = new PrintStream(client.getOutputStream(),true,"UTF-8");
            Scanner in = new Scanner(System.in);
            while (true){
                System.out.println("请输入要向服务器发送的信息..");
                String strFromUser = "";
                if (in.hasNext()){
                    strFromUser = in.nextLine();
                }
                //向服务器发送信息
                out.println(strFromUser);
                //byebye
                if (strFromUser.contains("byebye")){
                    System.out.println("当前客户端退出聊天室");
                    out.close();
                    in.close();
                    client.close();
                    break;
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class MutilThreadClient {
    public static void main(String[] args) throws IOException {
        //根据指定ip及端口号建立连接
        Socket client = new Socket("127.0.0.1",6666);
        //启动读线程和写线程
        Thread readThread = new Thread(new ReadFromServer(client));
        Thread sendThread = new Thread(new SendMsgToServer(client));
        readThread.start();
        sendThread.start();
    }
}

服务器:

import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Iterator;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Set;

public class MutilThreadServer {

    private static Map<String,Socket> clientLists = new ConcurrentHashMap<>();
    //专门用来处理每个客户端的输入,输出请求
    private static class ExecuteClientRequest implements Runnable{
        private Socket client;
        public ExecuteClientRequest(Socket client) {
            this.client = client;
        }
        @Override
        public void run() {
            try {
                //获取用户输入流,读取用户发来的信息
                Scanner in = new Scanner(client.getInputStream());
                String strFromClient = "";
                while (true){
                    if (in.hasNext()){
                        strFromClient = in.nextLine();
                    }
                    //windows下消除用户输入自带的\r
                    Pattern pattern = Pattern.compile("\r");
                    Matcher matcher = pattern.matcher(strFromClient);
                    strFromClient = matcher.replaceAll("");

                    /* 注册:username:xxx
                     * 群聊:G:群聊内容
                     * 私聊:P:用户名-私聊内容
                     * 用户退出:byebye*/
                    //注册流程
                    if (strFromClient.startsWith("username:")){
                        String username = strFromClient.split("\\:")[1];
                        Register(username,client);
                    }
                    //群聊流程
                    if (strFromClient.startsWith("G:")){
                        String groupMsg = strFromClient.split("\\:")[1];
                        groupChat(groupMsg);
                    }
                    //私聊
                    if (strFromClient.startsWith("P:")){
                        String username = strFromClient.split("\\:")[1].split("\\-")[0];
                        String privateMsg = strFromClient.split("\\:")[1].split("\\-")[2];
                        privateChat(username,privateMsg);
                    }
                    //用户退出:1:byebye
                    if(strFromClient.contains("byebye")){
                        String username = strFromClient.split("\\:")[0];
                        userOffLine(username);
                        break;
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        private void Register(String username,Socket socket){
            clientLists.put(username,socket);
            System.out.println("用户"+username+"上线了!当前聊天室人数为:"+clientLists.size());
            try {
                PrintStream out = new PrintStream(socket.getOutputStream(),true,"UTF-8");
                out.println("注册成功");
                out.println("当前聊天室人数为:"+clientLists.size());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        //群聊——遍历map,向每个客户端输出一遍
        private void groupChat(String groupMsg) throws IOException {
            Set<Map.Entry<String,Socket>> clientEntry = clientLists.entrySet();
            Iterator<Map.Entry<String,Socket>> iterator = clientEntry.iterator();
            while (iterator.hasNext()){
                //取出每一个客户端实体
                Map.Entry<String,Socket> client = iterator.next();
                //拿到客户端输出流输出群聊信息
                PrintStream out = new PrintStream(client.getValue().getOutputStream(),
                        true,"UTF-8");
                out.println("群聊信息为:"+groupMsg);
            }

        }
        //私聊
        private void privateChat(String username,String privateMsg) throws IOException {
            //取出username对应的Socket
            Socket client = clientLists.get(username);
            PrintStream out = new PrintStream(client.getOutputStream(),true,"UTF-8");
            out.println("私聊信息为:"+privateMsg);
        }
        private void userOffLine(String username){
            //删除map中的用户实体
            clientLists.remove(username);
            System.out.println("用户"+username+"已下线");

        }
    }
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(6666);
        //使用线程池来同时处理多个客户端连接
        ExecutorService executorService = Executors.newFixedThreadPool(20);
        System.out.println("等待客户端连接");
        for (int i=0;i<20;i++){
            Socket client = serverSocket.accept();
            System.out.println("有新的客户端连接,端口号为:"+client.getPort());
            executorService.submit(new ExecuteClientRequest(client));
        }
        //关闭线程池与服务端
        executorService.shutdown();
        serverSocket.close();
    }
}
posted @ 2021-10-24 23:13  impwa  阅读(141)  评论(0编辑  收藏  举报