在多人聊天室的基礎(chǔ)上增加了私聊功能。 實現(xiàn)方法:在Send類中添加name區(qū)別客戶端,用于客戶端;在MyChannel中添加name區(qū)別客戶端連接,用于服務(wù)端。 1.服務(wù)端
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
/**
* 創(chuàng)建服務(wù)器
* 發(fā)送數(shù)據(jù):輸出流
* 接收數(shù)據(jù):輸入流
*/
public class MyServer {
//存放服務(wù)端與客戶端的連接
private List<MyChannel> all = new ArrayList<>();
public static void main(String[] args) throws IOException {
new MyServer().start();
}
public void start() throws IOException {
ServerSocket server = new ServerSocket(8888);
while(true) {
Socket socket = server.accept();
MyChannel myChannel = new MyChannel(socket);
all.add(myChannel);
new Thread(myChannel).start();
}
}
/**
* 一個客戶端一條道路,
* 一個客戶端一個線程。
* 1.輸入流
* 2.輸出流
* 3.接收數(shù)據(jù)
* 4.發(fā)送數(shù)據(jù)
* 成員內(nèi)部類,靜態(tài)方法不能訪問。
*/
class MyChannel implements Runnable{
//輸入流
private DataInputStream dis;
//輸出流
private DataOutputStream dos;
//控制線程的標(biāo)識符
private boolean isRunning = true;
//名稱 給每個連接命名,區(qū)別客戶端 不考慮重名
private String name;
//初始化建立管道
public MyChannel(Socket socket) {
try {
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
name = dis.readUTF();
send("歡迎您進入聊天室!");//發(fā)送給自己客戶端
sendOthers(name + "進入了聊天室!", true); //發(fā)給其他的客戶端
} catch (IOException e) {
e.printStackTrace();
CloseUtil.closeAll(dis, dos);
all.remove(this);
isRunning = false;
}
}
//讀取數(shù)據(jù)
private String receive() {
String msg = "";
try {
msg = dis.readUTF();
} catch (IOException e) {
e.printStackTrace();
CloseUtil.closeAll(dis, dos);
all.remove(this);
isRunning = false;
}
return msg;
}
//發(fā)送給this數(shù)據(jù)
private void send(String msg) {
if(msg == null || msg.equals("")) {
return;
}
try {
dos.writeUTF(msg);
dos.flush();
} catch (IOException e) {
e.printStackTrace();
CloseUtil.closeAll(dis, dos);
all.remove(this);
isRunning = false;
}
}
//發(fā)送給其他客戶端
private void sendOthers(String msg, boolean isSysMsg) {
//是否為私聊
if(msg.startsWith("@") && msg.indexOf(":") != -1) {//向一個特定的人發(fā)消息,格式為@xxx:message
//獲取name
String name = msg.substring(1, msg.indexOf(":"));
//獲取內(nèi)容
String content = msg.substring(msg.indexOf(":") + 1);
for(MyChannel other:all) {
if(other.name.equals(name)) {
other.send(this.name + "對您悄悄地說:" + content);
}
}
} else {//向全體發(fā)消息
//遍歷容器
for(MyChannel other : all) {
if(other == this) {
continue;
}
if(isSysMsg) {//是系統(tǒng)消息
//發(fā)送給其他客戶端
other.send("系統(tǒng)信息:" + msg);
} else {//不是系統(tǒng)消息
//發(fā)送給其他客戶端
other.send(name + "對所有人說:" + msg);
}
}
}
}
@Override
public void run() {
while(isRunning) {
sendOthers(receive(), false);
}
}
}
}
2.客戶端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/**
* 創(chuàng)建客戶端:發(fā)送數(shù)據(jù)+接收數(shù)據(jù)
* 發(fā)送數(shù)據(jù):輸出流
* 接收數(shù)據(jù):輸入流
* 輸出流和輸入流應(yīng)該彼此獨立,使用線程處理。
* 加入名稱。
*/
public class MyClient {
public static void main(String[] args) throws IOException {
//通過名稱判斷不同的客戶 端,存放在Send類中。
System.out.println("請輸入名稱:");
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String name = br.readLine();
if(name.equals("")) {
return;
}
Socket client = new Socket("localhost", 8888);
//發(fā)送 控制臺輸入并發(fā)送到服務(wù)端
new Thread(new Send(client, name)).start();//一條路徑
//接收 接收服務(wù)端數(shù)據(jù)并打印
new Thread(new Receive(client)).start();//一條路徑
}
}
發(fā)送數(shù)據(jù)線程
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/**
* 發(fā)送數(shù)據(jù) 線程
*/
public class Send implements Runnable{
//控制臺輸入流
private BufferedReader console;
//管道輸出流
private DataOutputStream dos;
//控制線程的標(biāo)識符
private boolean isRunning = true;
//名稱 不考慮重名
private String name;
//初始化建立管道
public Send(Socket socket, String name) {
try {
console = new BufferedReader(new InputStreamReader(System.in));
dos = new DataOutputStream(socket.getOutputStream());
this.name = name;
send(name);
} catch (IOException e) {
e.printStackTrace();
isRunning = false;
CloseUtil.closeAll(dos, console);
}
}
/**
* 1.從控制臺接收數(shù)據(jù)
* 2.向服務(wù)端發(fā)送數(shù)據(jù)
*/
//1.從控制臺接收數(shù)據(jù)
private String getMsgFromConsole() {
String msg = "";
try {
msg = console.readLine();
} catch (IOException e) {
e.printStackTrace();
isRunning = false;
CloseUtil.closeAll(dos, console);
}
return msg;
}
//2.向服務(wù)端發(fā)送數(shù)據(jù)
private void send(String msg) {
try {
if(msg != null && !msg.equals("")) {
dos.writeUTF(msg);
dos.flush();//強制刷新
}
} catch (IOException e) {
e.printStackTrace();
isRunning = false;
CloseUtil.closeAll(dos, console);
}
}
@Override
public void run() {
//線程體
while(isRunning) {
send(getMsgFromConsole());
}
}
}
接收數(shù)據(jù)線程
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
public class Receive implements Runnable{
//輸入流
private DataInputStream dis;
//線程標(biāo)識符
private boolean isRunning = true;
//初始化建立管道
public Receive(Socket socket) {
try {
dis = new DataInputStream(socket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
isRunning = false;
CloseUtil.closeAll(dis);
}
}
/**
* 接收數(shù)據(jù)
*/
private String receive() {
String msg = "";
try {
msg = dis.readUTF();
} catch (IOException e) {
e.printStackTrace();
isRunning = false;
CloseUtil.closeAll(dis);
}
return msg;
}
@Override
public void run() {
//線程體
while(isRunning) {
System.out.println(receive());
}
}
}
3.關(guān)閉流工具類
import java.io.Closeable;
import java.io.IOException;
/**
* 關(guān)閉io流的工具
*/
public class CloseUtil {
public static void closeAll(Closeable... io) {
for(Closeable temp : io) {
try {
if(temp != null) {
temp.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
更多建議: