一、客户端
package com.bite;
//创建两个线程,1、从服务器读信息线程,2、将信息发送给服务器线程
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;
}
//覆写run()方法
public void run(){
try{
//获取客户端输入流
Scanner in=new Scanner(client.getInputStream());
in.useDelimiter("\n");
//不停的读取
while(true) {
if(in.hasNext()){
System.out.println("从服务器发来消息为:"+in.next());
}
if(client.isClosed()){
System.out.println("客户端已关闭");
break;
}
}
in.close();
}catch(IOException e){
System.out.println("客户端读线程异常");
}
}
}
//写线程
class WriteToServerThread implements Runnable{
private Socket client;
public WriteToServerThread(Socket client){
this.client=client;
}
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("客户端写线程异常");
}
}
}
public class MultiThreadClient {
public static void main(String[] args) {
try{
Socket client=new Socket("127.0.0.1",666);
//创建读写线程
Thread readFromServer=new Thread(new ReadFromServerThread(client));
Thread writeToServer=new Thread(new WriteToServerThread(client));
//启动读写线程
readFromServer.start();
writeToServer.start();
}catch(IOException e){
e.printStackTrace();
}
}
}
二、服务器端
package com.bite;
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
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<String, Socket> clientMap = new ConcurrentHashMap<String, Socket>(); //相同名字注册时,存在线程安全问题,采用ConcurrentHashMap可以避免线程安全问题
//具体处理与每个客户端通信的内部类
private static class ExecuteClient implements Runnable {
private Socket client;
public ExecuteClient(Socket client) {
this.client = client;
}
public void run() {
try {
//获取客户端输入流
Scanner in = new Scanner(client.getInputStream());
String strFromClient="";
while (true) {
if (in.hasNextLine()) {
strFromClient = in.nextLine();
// windows下将默认换行/r/n中的/r替换为空字符串
Pattern pattern = Pattern.compile("\r");
Matcher matcher = pattern.matcher(strFromClient);
strFromClient = matcher.replaceAll("");
// 注册流程
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.contains("byebye")) {
String userName = null;
// 根据Socket找到UserName
for (String keyName : clientMap.keySet()) {
if (clientMap.get(keyName).equals(client)) {
userName = keyName;
}
}
System.out.println("用户" + userName + "下线了!");
clientMap.remove(userName);
System.out.println("当前群聊人数为:"+(clientMap.size()+1)+"人");
continue;
}
}
}
} catch (IOException e) {
System.err.println("服务器通信异常,错误为 " + e);
}
}
}
//注册方法
private static void registerUser(String userName,Socket client){
System.out.println("用户名为:"+userName);
System.out.println("用户"+userName+"上线了");
System.out.println("当前群聊人数为:"+(clientMap.size()+1)+"人");
//将用户信息保存到map中
clientMap.put(userName,client);
try{
PrintStream out= new PrintStream(client.getOutputStream(),
true,"UTF-8");
// 告知用户注册成功
out.println("用户注册成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
// 群聊流程
private static void groupChat(String msg) {
// 取出clientMap中所有Entry遍历发送群聊信息
Set<Map.Entry<String,Socket>> clientSet = clientMap.entrySet();
for (Map.Entry<String,Socket> entry : clientSet) {
try {
Socket socket = entry.getValue();
// 取得每个客户端的输出流
PrintStream out = new PrintStream(socket.getOutputStream(),
true,"UTF-8");
out.println("群聊信息为: "+msg);
}catch (IOException e) {
System.err.println("群聊异常,错误为 "+e);
}
}
}
// 私聊流程
private static void privateChat(String userName,String msg) {
Socket privateSocket = clientMap.get(userName);
try {
PrintStream out = new PrintStream(privateSocket.getOutputStream(),
true,"UTF-8");
out.println("私聊信息为: "+msg);
}catch (IOException e) {
System.err.println("私聊异常,错误为"+e);
}
}
public static void main(String[] args) throws Exception{
ExecutorService executorService = Executors.newFixedThreadPool(20);
//建立基站
ServerSocket serverSocket = new ServerSocket(666);
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();
}
}