TCP多人聊天室的實現
1. 功能分析
1.1 客戶端
- 功能:
- 數據發送
- 數據接收
- 聊天:
- 羣聊
- 私聊
1.2 服務器
- 功能:
- 數據轉發
- 用戶註冊
- 數據轉發判斷:
- 私聊
- 羣聊
我們需要知道一點:一個用戶對應着一個socket,所以我們需要將用戶和socket進行綁定,我們可以使用Map來進行存儲,Key用來存儲用戶id,Value用來存儲對應的socket
代碼
1. 服務器
public class Server{
private HashMap<Integer, UserSocket> userMap;
//累計訪問人數,作爲用戶的id(userMap中的Key值)
private static int count = 0;
//初始化
public Server () {
userMap = new HashMap<>();
}
//服務器啓動方法
public void start() throws IOException {
//啓動服務器,監聽端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服務器啓動");
while (true) {
//接收用戶請求
Socket socket = serverSocket .accept();
count += 1;
UserSocket userSocket = new UserSocket(count, socket);
userMap.put(count, userSocket);
// 啓動當前UserSocket服務
new Thread(userSocket).start();
}
}
class UserSocket implements Runnable {
private DataInputStream inputstream;
private DataOutputStream outputStream;
//用戶id
private int userId;
//用戶名 ,這個是剛開始註冊的時候客戶端發送給服務器的
private String userName;
//連接標記
private boolean connection;
//構造方法
public UserSocket(int userId, Socket socket) {
this.userId = userId;
try {
inputStream = new DataInpuStream(socket.getInputStream());
outputStream = new DataOutputStream(socket.getOutputStream());
connection = true;
} catch (IOException e) {
e.printStackTrace();
connetion = false;
}
try {
this.userName = InputStream.readUTF();
//廣播所有人XXX上線了,自己除外
sendOther ("ID:" + this.userId + " " + this.userName + "來到直播間", true);
send("歡迎來到聊天室");
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* 接收客戶端發送的數據,用於轉發操作
*/
public String receive() {
String msg = null;
try {
msg = inputStream.readUTF();
} catch (IOException e) {
e.printStackTrace();
connetion = false;
//設置的工具類,關閉資源
CloseUtil.closeAll(inputStream, outputStream);
}
return msg;
}
/*
* 發送數據到客戶端
*/
public void send(String msg) {
try{
outputStream.writeUTF(msg);
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
connetion = false;
CloseUtil.closeAll(inputStream, outputStream);
}
}
public void sendOther(String msg, boolean sys) {
//私聊@1:XXXXXX
if (msg.startsWith("@") && msg.contains(":")) {
//獲取私聊的id
Integer id = Integer.parseInt(msg.substring(1, msg.indexOf(":")));
String newMsg = msg.substring(msg.indexOf(":"));
UserSocket userSocket = userMap.get(id);
if (userSocket != null) {
userSocket.send("ID:" + this.userId + " " + this.userName + "悄悄的對你說" + newMsg);
}
} else {
//羣聊
Collection<UserSocket> values = userMap.values();
for (UserSocket userSocket : values) {
if (userSocket != this) {
// 判斷是不是系統消息
if (sys) {
userSocket.send("系統公告:" + msg);
} else {
userSocket.send("ID:" + this.userId + " " + this.userName + msg);
}
}
}
}
}
@Override
public void run() {
while (connetion) {
// 使用receive收到的消息作爲參數,同時標記非系統消息,調用sendOther
sendOther(receive(), false);
}
}
}
public static void main (String[] args) {
Server server = new Server();
try {
server.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. 工具類
3. 客戶端
3.1
3.2 ClientSend
public calss ClientSend implements Runnable {
private DataOutputStream outputStream;
private BufferedReader console;
private boolean connection;
public ClientSend(Socket socket, String userName) {
try {
outputStream = new DataOutputStream(socket.getOutputStream());
console = new BufferedReader(new InputStreamReader(System.in));
send(userName);
connection = true;
} catch (IOException e) {
e.printStackTrace();
connection = false;
CloseUtil.closeAll(outputStream, console);
}
}
//從鍵盤上獲取用戶輸入的數據
public String getMsgFromConsole() {
String msg = null;
try {
// 從鍵盤上讀取一行數據
msg = console.readLine();
} catch (IOException e) {
e.printStackTrace();
connection = false;
CloseUtil.closeAll(outputStream, console);
}
return msg;
}
//發送數據給服務器
public void send(String msg) {
try {
if (msg != null && !"".equals(msg)) {
outputStream.writeUTF(msg);
outputStream.flush();
}
} catch (IOException e) {
e.printStackTrace();
connection = false;
CloseUtil.closeAll(outputStream, console);
}
}
@Override
public void run() {
while (connection) {
send(getMsgFromConsole());
}
}
}
3.3 ClientReceive
public class ClientReceive implements Runnable {
private DataInputStream inputStream;
private boolean connection;
public ClientReceive(Socket socket) {
try {
inputStream = new DataInputStream(socket.getInputStream());
connection = true;
} catch (IOException e) {
e.printStackTrace();
connection = false;
}
}
public void receive() {
String msg = null;
try {
msg = inputStream.readUTF();
} catch (IOException e) {
e.printStackTrace();
connection = false;
CloseUtil.closeAll(inputStream);
}
System.out.println(msg);
}
@Override
public void run() {
while (connection) {
receive();
}
}
}
4. 效果