package com.company;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.SQLOutput;
import java.util.Map;
import java.util.Scanner;
import java.util.Set;
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;
/**
* 多线程聊天室服务器端
*/
public class MultiThreadServer {
//存储所有的注册的客户端
private static Map
//具体处理与每一个客户端通信的内部类
private static class ExecuteClient implements Runnable {
private Socket client;
private ExecuteClient(Socket client) {
this.client = client;
}
@Override
public void run() {
try {
//获取客户端输入流
Scanner in = new Scanner(client.getInputStream());
String strFromClient;
while (true) {
if (in.hasNextLine()) {
strFromClient = in.next();
//windows下默认的换行符为\r\n
//使用正则表达式将默认换行符替换为\n
Pattern pattern = Pattern.compile("\r"); //匹配对应的“\r”字符
Matcher matcher = pattern.matcher(strFromClient);//返回被比较的对象strFromClient
strFromClient = matcher.replaceAll(" ");//替换strFromClient中的”\r"为空格“ ”
//用户注册
if(strFromClient.startsWith("userName")){
String userName=strFromClient.split("\\:")[1];
registerUser(userName,client);
continue;
}
//群聊流程
if(strFromClient.startsWith("G")){
String msg=strFromClient.split("\\:")[1];
groupChat(msg);
continue;
}
//私聊流程
if(strFromClient.startsWith("P")){
String userName=strFromClient.split("\\:")[1]
.split("\\-")[0];
String msg=strFromClient.split("\\:")[1]
.split("\\-")[1];
privateChat(userName,msg);
}
//用户退出
if(strFromClient.equals("byebye")){
String usename=null;
for(String keyName:clientMap.keySet()){
if(clientMap.get(keyName).equals(client)){
usename=keyName;
}
}
System.out.println("用户:"+usename+"下线了");
System.out.println("当前用户人数为"+(clientMap.size()-1)+"人");
clientMap.remove(usename);
continue;
}
}
}
} catch (IOException e) {
System.out.println("服务器通信异常,异常为:"+e);
}
}
//用户注册
private void registerUser(String userName, Socket client) {
System.out.println("用户名为:" + userName);
System.out.println("用户" + userName + "上线啦");
System.out.println("当前群聊人数为:" + (clientMap.size() + 1 )+ "人");
//将用户信息保存到clientMapzhong
clientMap.put(userName, client);
try {
//取得对应用户的输出流
PrintStream out = new PrintStream(client.getOutputStream(),
true, "utf-8");
//告诉用户注册成功
out.println("用户注册成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
//群聊流程
private void groupChat(String msg) {
//取出当前所有的用户端口,发送群消息
Set
for (Map.Entry
//取得用户端口
Socket socket = entry.getValue();
try {
//取得用户的输出流
PrintStream out = new PrintStream(socket.getOutputStream(),
true, "utf-8");
//通过输出流向用户发送消息
out.println("群聊消息为:" + msg);
} catch (IOException e) {
System.out.println("群聊异常,错误为:" + e);
}
}
}
//私聊流程
private void privateChat(String userName, String msg) {
//在注册表中查找对应的用户的socket
Socket privateSocket = clientMap.get(userName);
try {
//获取指定用户的输出流
PrintStream out = new PrintStream(privateSocket.getOutputStream(),
true, "utf-8");
//向指定用户发送消息
out.println("私聊消息为"+msg);
} catch (IOException e) {
System.out.println("私聊异常,错误为:" + e);
}
}
}
public static void main(String[] args) throws IOException {
//创建一个定长为20的线程池
ExecutorService executorService= Executors.newFixedThreadPool(20);
//绑定本地ip,定制端口号
ServerSocket serverSocket=new ServerSocket(9999);
for(int i=0;i<20;i++){
System.out.println("等待客户端连接:。。。");
//连接客户端
Socket client=serverSocket.accept();
System.out.println("有新的客户端连接成功,端口号为:"+client.getPort());
//启动线程
executorService.submit(new ExecuteClient(client));
}
executorService.shutdown();
serverSocket.close();
}
}
聊天室客户端:
import javax.lang.model.util.SimpleAnnotationValueVisitor6;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
/**
* 读取服务器发来的消息线程
*/
class ReadFromServerThread implements Runnable{
private Socket client;
public ReadFromServerThread (Socket client) {
this.client=client;
}
@Override
public void run() {
try {
//获取客户端输入流
Scanner in=new Scanner(client.getInputStream());
in.useDelimiter("\n");
while(true){
if(in.hasNextLine()){
System.out.println("当前收到服务器转发的消息"+in.next());
}
//此客户端退出
if(client.isClosed()){
System.out.println("客户端已关闭"+client.getPort()); // 输出关闭的端口号
break;
}
}
in.close();
} catch (IOException e) {
System.out.println("客户端读线程异常,错误为:"+e);
}
}
}
/**
* 将消息发送给服务器
*/
class WriteToServerThread implements Runnable{
private Socket client;
public WriteToServerThread(Socket client) {
this.client = client;
}
@Override
public void run() {
try {
//获取客户端输入流,从键盘输入
Scanner scanner=new Scanner(System.in);
scanner.useDelimiter("\n");
//获取客户端输出流,将消息发送给服务器
PrintStream out=new PrintStream(client.getOutputStream());
while(true){
System.out.println("请输入要发送的消息:");
String strToServer;
if(scanner.hasNextLine()){
strToServer=scanner.nextLine().trim();
out.println(strToServer);
//客户端退出标志
if(strToServer.equals("byebye")){
System.out.println("关闭客户端");
scanner.close();
out.close();
client.close();
break;
}
}
}
} catch (IOException e) {
System.out.println("客户端写线程异常,发生的错误为:"+e);
}
}
}
/**
* 多线程的聊天室客户端
*/
public class MultiThreadClient {
public static void main(String[] args) {
try {
//连接指定端口
Socket client=new Socket("127.0.0.1",9999);
//读取服务器消息线程
Thread readFromSever=new Thread(new ReadFromServerThread(client));
//写入消息给服务器线程
Thread writeToServer=new Thread(new WriteToServerThread(client));
//启动线程
readFromSever.start();
writeToServer.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}