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(); } }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· 《HelloGitHub》第 106 期
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 数据库服务器 SQL Server 版本升级公告
· 深入理解Mybatis分库分表执行原理
· 使用 Dify + LLM 构建精确任务处理应用
2020-10-24 p_value
2020-10-24 p_value