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 @   impwa  阅读(144)  评论(0编辑  收藏  举报
编辑推荐:
· 深入理解 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
点击右上角即可分享
微信分享提示