总体思路:多个客户端和服务端建立连接,客户端之间通过服务端做中转站传输数据
服务端
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();
}
}
}
}
}