- 客戶端代碼
package chat.room.server;
import java.net.Socket;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Scanner;
//客戶端讀取服務器端信息的線程
class ClientReadServer implements Runnable{
private Socket socket;
public ClientReadServer(Socket socket){
this.socket = socket;
}
public void run(){
//獲取服務器端輸入流
Scanner scanner;
try {
scanner = new Scanner(socket.getInputStream());
while(scanner.hasNext()){
System.out.println(scanner.next());
}
scanner.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
//客戶端向服務器發送信息的線程
class ClientSendServer implements Runnable{
private Socket socket;
public ClientSendServer(Socket socket){
this.socket = socket;
}
public void run(){
try {
//獲取服務器端的輸出流
PrintStream printStream = new PrintStream(socket.getOutputStream());
//從鍵盤輸入信息
Scanner scanner = new Scanner(System.in);
while(true){
String msg = null;
if(scanner.hasNext()){
msg = scanner.next();
printStream.println(msg);
}
if(msg.equals("exit")){
scanner.close();
printStream.close();
break;
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class MultiClient{
public static void main(String[] args) throws IOException{
//客戶端連接服務器端,返回套接字Socket對象
Socket socket = new Socket("127.0.0.1",6666);
//創建讀取服務器端信息的線程和發送服務器端信息的線程
Thread read = new Thread(new ClientReadServer(socket));
Thread send = new Thread(new ClientSendServer(socket));
//啓動線程
read.start();
send.start();
}
}
- 服務器端代碼
package chat.room.server;
import java.net.Socket;
import java.net.ServerSocket;
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;
import java.io.PrintStream;
import java.io.IOException;
class Server implements Runnable{
private static Map<String,Socket> map = new ConcurrentHashMap<String,Socket>();
private Socket socket;
public Server(Socket socket){
this.socket = socket;
}
public void run(){
//獲取客戶端的輸入流
try{
Scanner scanner = new Scanner(socket.getInputStream());
String msg = null;
while(true){
if(scanner.hasNextLine()){
//處理客戶端輸入的字符串
msg = scanner.nextLine();
Pattern pattern = Pattern.compile("\r");
Matcher matcher = pattern.matcher(msg);
msg = matcher.replaceAll("");
//1.註冊用戶流程,註冊用戶格式爲:userName:用戶名
if(msg.startsWith("userName:")){
//將用戶名保存在userName中
String userName = msg.split("\\:")[1];
//註冊用戶
userRegist(userName,socket);
continue;
}
//2.羣聊信息流程,羣聊的格式爲:G:羣聊信息
else if(msg.startsWith("G:")){
//必須先註冊纔可以
firstStep(socket);
//保存羣聊信息
String str = msg.split("\\:")[1];
//發送羣聊信息
groupChat(socket,str);
continue;
}
//3.私聊信息流程,私聊的格式爲:P:userName-私聊信息
else if(msg.startsWith("P:")&&msg.contains("-")){
//必須先註冊纔可以
firstStep(socket);
//保存需要私聊的用戶名
String userName = msg.split("\\:")[1].split("-")[0];
//保存私聊的信息
String str = msg.split("\\:")[1].split("-")[1];
//發送私聊信息
privateChat(socket,userName,str);
continue;
}
//4.用戶退出流程,用戶退出格式爲:包含exit
else if(msg.contains("exit")){
//必須先註冊纔可以
firstStep(socket);
userExit(socket);
continue;
}
//其他輸入格式均錯誤
else{
PrintStream printStream = new PrintStream(socket.getOutputStream());
printStream.println("輸入格式錯誤,請按照以下格式輸入");
printStream.println("註冊用戶格式:[userName:用戶名]");
printStream.println("羣聊格式:[G:羣聊信息]");
printStream.println("私聊格式:[P:userName-私聊信息]");
printStream.println("用戶退出格式[包含exit即可]");
continue;
}
}
}
}catch(IOException e){
e.printStackTrace();
}
}
private void firstStep(Socket socket) throws IOException {
Set<Map.Entry<String,Socket>> set=map.entrySet();
for(Map.Entry<String,Socket> entry:set){
if(entry.getValue().equals(socket)){
if(entry.getKey()==null){
PrintStream printStream=new PrintStream(socket.getOutputStream());
printStream.println("請先進行註冊操作!");
printStream.println("註冊格式爲:[userName:用戶名]");
}
}
}
}
private void userRegist(String userName,Socket socket){
map.put(userName,socket);
System.out.println("[用戶名爲"+userName+"][客戶端爲"+socket+"]上線了!");
System.out.println("當前在線人數爲:"+map.size()+"人");
}
private void userExit(Socket socket){
//利用socket取得對應的key值
String userName = null;
for(String key:map.keySet()){
if(map.get(key).equals(socket)){
userName = key;
break;
}
}
//將userName,Socket元素從map集合中刪除
map.remove(userName,socket);
//提醒服務器客戶端已下線
System.out.println("用戶:"+userName+"已下線");
}
private void privateChat(Socket socket,String userName,String msg) throws IOException{
//取得當前客戶端的用戶名
String curUser = null;
Set<Map.Entry<String,Socket>> set=map.entrySet();
for(Map.Entry<String, Socket> entry:set){
if(entry.getValue().equals(socket)){
curUser = entry.getKey();
break;
}
}
//取得私聊用戶名對應的客戶端
Socket client = map.get(userName);
//獲取私聊客戶端的輸出流,將私聊信息發送到指定客戶端
PrintStream printStream = new PrintStream(client.getOutputStream());
printStream.println(curUser+"私聊說:"+msg);
}
private void groupChat(Socket socket,String msg) throws IOException{
//將Map集合轉換爲Set集合
Set<Map.Entry<String,Socket>> set = map.entrySet();
//遍歷Set集合找到發起羣聊信息的用戶
String userName = null;
for(Map.Entry<String, Socket> entry:set){
if(entry.getValue().equals(socket)){
userName = entry.getKey();
break;
}
}
//遍歷Set集合將羣聊信息發給每一個客戶端
for(Map.Entry<String,Socket> entry:set){
//取得客戶端的Socket對象
Socket client = entry.getValue();
//取得client客戶端的輸出流
PrintStream printStream = new PrintStream(client.getOutputStream());
printStream.println(userName+"羣聊說:"+msg);
}
}
}
public class MultiServer{
public static void main(String[] args){
try{
//1.創建服務器端的ServerSocket對象,等待客戶端連接
ServerSocket serverSocket = new ServerSocket(6666);
//2.創建線程池,從而可以處理多個客戶端
ExecutorService executorService = Executors.newFixedThreadPool(20);
for(int i=0;i<20;i++){
System.out.println("歡迎來到我的聊天室……");
//3.監聽客戶端
Socket socket = serverSocket.accept();
System.out.println("有新的朋友加入……");
//啓動線程
executorService.execute(new Server(socket));
}
//關閉線程池
executorService.shutdown();
//關閉服務器
serverSocket.close();
} catch(IOException e){
e.printStackTrace();
}
}
}