服务端
多线程聊天室服务端的基本框架和整体思路如下图
多线程聊天室服务端代码
package com.bittch.chatroom.server;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 多线程聊天室服务端
* Auther:CHAOQIWEN
*/
public class MulThreadServer {
public static void main(String[] args) {
try {
ServerSocket serverSocket = new ServerSocket(6666);
System.out.println("服务器启动.."+serverSocket.getLocalSocketAddress());
//线程池
ExecutorService executorService = Executors.newFixedThreadPool(25);
while(true){
Socket client = serverSocket.accept();
System.out.println(""+client.getRemoteSocketAddress());
executorService.execute(new HandlerClient(client));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
HandlerClient接口的实现:
package com.bittch.chatroom.server;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.ConcurrentHashMap;
/**
* Auther:CHAOQIWEN
*/
public class HandlerClient implements Runnable {
//维护所有的连接到服务端的客户端对象
private static final Map<String,Socket> ONLINE_CLIENT_MAP = new ConcurrentHashMap<>();
private final Socket client;
public HandlerClient(Socket client) {
this.client = client;
}
@Override
public void run() {
try {
InputStream clientInput = client.getInputStream();
Scanner scanner = new Scanner(clientInput);
//消息按行读取
//1 、注册:register : <userName> register:张三
//2 、群聊:groupChat: <message> groupChat:大家好
//3 、私聊:privateChat: <userName>:<message> privateChat:你好
//4、 退出:bye
while (true) {
String data = scanner.nextLine();
if (data.startsWith("register:")) {
String userName = data.split(":")[1];
register(userName);
continue;
}
if (data.startsWith("groupChat:")) {
String message = data.split(":")[1];
groupChat(message);
continue;
}
if (data.startsWith("privateChat:")) {
String[] segments = data.split(":");
String targetUserName = segments[1];
String message = segments[2];
privateChat(targetUserName, message);
continue;
}
if (data.equals("bye")) {
bye();
continue;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
//退出
private void bye() {
for(Map.Entry<String,Socket> entry:ONLINE_CLIENT_MAP.entrySet()){
Socket target = entry.getValue();
if(target.equals(this.client)){
ONLINE_CLIENT_MAP.remove(entry.getKey());
break;
}
}
printOnlineClient();;
}
private String getCurrentUserName(){
for(Map.Entry<String,Socket> entry:ONLINE_CLIENT_MAP.entrySet()){
Socket target = entry.getValue();
if(target.equals(this.client)){
return entry.getKey();
}
}
return "";
}
//私聊,给targetUserName发送message消息
private void privateChat(String targetUserName,String message) {
Socket target = ONLINE_CLIENT_MAP.get(targetUserName);
if(target == null){
this.sendMessage(this.client,"没这个人"+targetUserName,false);
}else {
String currentUserName = this.getCurrentUserName();
this.sendMessage(target,"<"+currentUserName+":说>"+message,true);
}
}
//群聊发送message
private void groupChat(String message) {
for(Map.Entry<String,Socket> entry:ONLINE_CLIENT_MAP.entrySet()){
Socket target = entry.getValue();
if(target.equals(this.client)){
continue;
}
this.sendMessage(target,message,true);
}
}
//以userName为key注册当前用户
private void register(String userName) {
ONLINE_CLIENT_MAP.put(userName,client);
printOnlineClient();
this.sendMessage(this.client,userName+"注册成功",false);
}
private void sendMessage(Socket target,String message ,boolean prefix){
OutputStream clientOutput = null;
try {
clientOutput =target.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(clientOutput);
if(prefix){
String currentUserName = this.getCurrentUserName();
writer.write("<"+currentUserName+":说>"+message+"\n");
}else {
writer.write(message+"\n");
}
writer.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
//打印在线客户端
private void printOnlineClient(){
System.out.println("在线人数"+ONLINE_CLIENT_MAP.size()+"用户名如下");
for(String userName : ONLINE_CLIENT_MAP.keySet()){
System.out.println(userName);
}
}
}
客户端
多线程聊天室客户端的基本框架和整体思路如下图
多线程聊天室客户端代码:
package com.bittch.chatroom.client;
import java.io.IOException;
import java.net.Socket;
/**
* Auther:CHAOQIWEN
*/
public class MulThreadClient {
public static void main(String[] args) {
try {
Socket client = new Socket("127.0.0.1",6666);
new ReadDataFromServerThread(client).start();
new WriteDataToServerThread(client).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
ackage com.bittch.chatroom.client;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Scanner;
/**
* 客户端从服务端读取数据的线程
* Auther:CHAOQIWEN
*/
public class ReadDataFromServerThread extends Thread{
private final Socket client;
public ReadDataFromServerThread(Socket client){
this.client = client;
}
@Override
public void run() {
try {
InputStream clientInput = this.client.getInputStream();
Scanner scanner = new Scanner(clientInput);
while(true){
String data = scanner.nextLine();
System.out.println("来自服务端消息"+data);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.bittch.chatroom.client;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
/**
* 客户端给服务端发送的数据
* 发送的数据来自命令行的交互式输入
* Auther:CHAOQIWEN
*/
public class WriteDataToServerThread extends Thread {
private final Socket client;
public WriteDataToServerThread(Socket client){
this.client = client;
}
@Override
public void run() {
try {
OutputStream clientOutput = this.client.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(clientOutput);
Scanner scanner = new Scanner(System.in);
while(true){
System.out.println("请输入>>");
String data = scanner.nextLine();
writer.write(data+"\n");
writer.flush();
if(data.equals("bye")){
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}