總體思路:多個客戶端和服務端建立連接,客戶端之間通過服務端做中轉站傳輸數據
服務端
package com.ck.chat;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
public class Server {
//用於存儲對應用戶的chat對象
private Map<String,Chat> chats = new HashMap<String,Chat>();
public Server() throws IOException {
// 創建服務器並指定端口
ServerSocket server = new ServerSocket(8888);
while (true) {
// 接收請求
Socket client = server.accept();
System.out.println("一個客戶端建立連接,ip地址:" + client.getInetAddress() + " 端口:" + client.getPort());
//生成聊天對象
new Thread(){
public void run(){
try {
DataInputStream dis = new DataInputStream(client.getInputStream());
//接收用戶的名字
String name = dis.readUTF();
//判斷用戶是否已存在
Chat hasChat = chats.get(name);
Chat chat = new Chat(Server.this,client,name);
if(hasChat == null){
System.out.println("用戶(" + name + ")成功登錄");
chats.put(name, chat);
}else{
chat.sendToClient("你已登錄");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
}
public static void main(String[] args) {
try {
new Server();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 服務器轉發消息
* @param recvName 接收者名字
* @param message 消息內容
* @throws IOException
*/
public void send(String recvName, String message) throws IOException {
//得到接受者的聊天對象
Chat chat = chats.get(recvName);
//調用chat的發送消息方法
chat.sendToClient(message);
}
}
客戶端
package com.ck.chat;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public Client() {
DataOutputStream dos = null;
try {
// 指定服務器地址+端口
Socket client = new Socket("localhost", 8888);
System.out.print("請輸入用戶名:");
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
dos = new DataOutputStream(client.getOutputStream());
dos.writeUTF(getMsgFromConsole(console));
dos.flush();
new Chat(null,client,null);
} catch (UnknownHostException e) {
e.printStackTrace();
CloseUtil.closeAll(dos);
} catch (IOException e) {
e.printStackTrace();
CloseUtil.closeAll(dos);
}
}
public static void main(String[] args) throws UnknownHostException, IOException {
new Client();
}
private String getMsgFromConsole(BufferedReader console) {
try {
return console.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
Chat對象
package com.ck.chat;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/**
* 聊天對象,用於實現數據的發送和接收
* @author sansheng__
*
*/
public class Chat {
private boolean clientIsRuning = true;
private boolean serverIsRuning = true;
private DataOutputStream dos;
public Chat(Server server, Socket socket, String sendName) throws IOException {
final DataInputStream dis = new DataInputStream(socket.getInputStream());
final DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
final BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
this.dos = dos;
/**
* 客戶端
*/
if (server == null) {
/**
* 接收消息
*/
new Thread() {
public void run() {
while (clientIsRuning) {
try {
String msg = dis.readUTF();
System.out.println(msg);
if("你已登錄".equals(msg)){
socket.close();
}
} catch (Exception e) {
e.printStackTrace();
clientIsRuning = false;
CloseUtil.closeAll(dis);
}
}
}
}.start();
/**
* 發送消息
*/
new Thread() {
public void run() {
while (clientIsRuning) {
try {
// 讀取客戶端發送的消息
String msg = console.readLine();
// 輸入byebye結束連接
if ("byebye".equalsIgnoreCase(msg)) {
socket.close();
clientIsRuning = false;
}
if (msg != null && !"".equals(msg)) {
dos.writeUTF(msg);
dos.flush();
}
} catch (IOException e) {
e.printStackTrace();
clientIsRuning = false;
CloseUtil.closeAll(dos);
}
}
}
}.start();
}
/**
* 服務端-接收消息
*/
if (server != null) {
new Thread() {
public void run() {
while (serverIsRuning) {
try {
String msg = dis.readUTF();
// System.out.println("客戶端消息:" + msg);
int index1 = msg.indexOf(":");
int index2 = msg.indexOf(",");
if (index1 < 0) {
// 沒有消息 服務器不轉發
System.out.println(msg);
} else {
// 有消息 服務器轉發消息給對應的客戶端
if (index2 < 0) {
// 私聊 xxx:你好
String recvName = msg.substring(0, index1);
String message = msg.substring(index1 + 1);
// 服務器發消息
server.send(recvName, sendName + "對你說:" + message);
} else {
// 羣聊 xxx,xxx,xxx:你好
String[] recvNames = msg.substring(0, index1).split(",");
String message = msg.substring(index1 + 1);
for (String name : recvNames) {
server.send(name, sendName + "對你們說:" + message);
}
}
}
} catch (IOException e) {
e.printStackTrace();
serverIsRuning = false;
CloseUtil.closeAll(dis);
}
}
}
}.start();
}
}
/**
* 服務器給客戶端發送消息
*
* @param message
* @throws IOException
*/
public void sendToClient(String message) throws IOException {
dos.writeUTF(message);
dos.flush();
}
}
CloseUtil
package com.ck.chat;
import java.io.Closeable;
import java.io.IOException;
/**
* 關流工具類
* @author sansheng__
*
*/
public class CloseUtil {
public static void closeAll(Closeable... ios) {
for(Closeable temp : ios){
if(temp != null){
try {
temp.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}