上一篇写了使用 socket 实现群聊的功能,但是有点缺陷比如说说话的时候没有显示是谁说的,没有私聊,之类的
其实加个 客户端说话的时候是谁说的很简单,无非就是 获取当前客户端的用户名,私聊的话就是 发送给其他客户端的时候再进行限制一下,发给我指定的,比如说 @zzq:lcm 就是我对zzq说 lcm,约定 以 @ 开头,:结尾的中间的就是我们at的人。
所以这里我们在new 客户端的时候就应该给客户端加个用户名了,然后 初始化的时候输入用户名,发送消息线程 实例化的时候给服务端发送该客户端的用户名
改动后的代码:
客户端 ClientSend 类:
/**
* 发送数据线程
* @author snow
*
*/
public class ClientSend implements Runnable {
private BufferedInputStream bis;
private BufferedOutputStream bos;
private Socket client;
private boolean isRuning = true ;
private String name;
/**
* 构造器初始化
* @param client 客户端
* @param name 聊天室的用户名
*/
public ClientSend(Socket client,String name) {
this.bis = new BufferedInputStream( System.in );
this.client = client;
try {
this.bos = new BufferedOutputStream( this.client.getOutputStream() );
// 初始化完成后给服务端发送用户名
this.name = name;
this.send(name);
} catch (IOException e) {
e.printStackTrace();
isRuning = false;
CloseUtil.closeAll(bos,bis,client);
}
}
/**
* 获取控制台输入的数据
* @return
*/
private String getMsg() {
byte [] data = new byte[1024];
int len = 0;
try {
len = bis.read(data);
} catch (IOException e) {
e.printStackTrace();
isRuning = false;
CloseUtil.closeAll(bos,bis,client);
}
return new String(data , 0 ,len);
}
/**
* 发送消息
*/
public void send(String msg) {
try {
this.bos.write(msg.getBytes());
this.bos.flush();
} catch (IOException e) {
e.printStackTrace();
isRuning = false;
CloseUtil.closeAll(bos,bis,client);
}
}
@Override
public void run() {
while(isRuning) {
String msg = getMsg();
send(msg);
}
}
}
MyClient类:
public static void main(String[] args) throws UnknownHostException, IOException {
Socket client = new Socket("127.0.0.1", 9999);
System.out.println("请输入您的用户名:");
String name = new BufferedReader( new InputStreamReader(System.in) ).readLine();
// 发送消息
new Thread(new ClientSend(client,name)).start();
// 接收消息
new Thread(new ClientReceive(client)).start();
}
服务端 Server类 :
/**
* 服务端的 server
* @author snow
*
*/
public class Server implements Runnable {
private BufferedInputStream bis ;
private BufferedOutputStream bos;
private Socket server;
private boolean isRuning = true;
private ArrayList<Server> clients;
private String clientName;
public Server(Socket server,ArrayList<Server> clients) {
try {
this.bis = new BufferedInputStream( server.getInputStream() );
this.bos = new BufferedOutputStream( server.getOutputStream() );
this.server = server;
this.clients = clients;
// 获取客户端用户名
this.clientName = this.receviceMsg();
// 给当前客户端发送欢迎消息
this.sendMsg("欢迎来到聊天室");
// 给其他客户端发送提示信息,系统消息
this.sendMsgToAllClient("["+clientName+"]已加入聊天室",true);
} catch (IOException e) {
e.printStackTrace();
isRuning = false;
CloseUtil.closeAll(server,bos,bis);
}
}
/**
* 接收数据
* @return
*/
private String receviceMsg() {
byte [] data = new byte[1024];
int len = 0;
try {
len = this.bis.read(data);
} catch (IOException e) {
e.printStackTrace();
isRuning = false;
CloseUtil.closeAll(server,bos,bis);
}
return new String(data, 0, len);
}
/**
* 发送消息
*/
private void sendMsg(String data) {
try {
this.bos.write(data.getBytes());
this.bos.flush();
} catch (IOException e) {
e.printStackTrace();
isRuning = false;
CloseUtil.closeAll(server,bos,bis);
}
}
/**
* 发送给另外的客户端消息
*/
private void sendMsgToAllClient(String msg,boolean isSysMsg) {
// 约定以 @ 开头,: 结尾的中间的为私聊的用户名,比如说 @zzq:lcm 就是 我对 zzq 说 lcm
if( msg.startsWith("@") && msg.indexOf(":")>-1 ) {
String atName = msg.substring(1,msg.indexOf(":")); // @zzq@lcm@1219:
String[] atNames = atName.split("@"); // 获取所有 被at的人
String content = msg.substring(msg.indexOf(":")+1); // 获取发送的消息
// 系统给 @ 的用户名的客户端发送消息
for (Server other : clients) {
for (String name : atNames) {
if(other.clientName.equals(name)) {
other.sendMsg("[" + this.clientName + "]" + "悄悄的对你说:" + content);
}
}
}
}else {
for (Server server : clients) {
if( server == this ) {
continue;
}
if(isSysMsg) {
server.sendMsg("【系统消息】"+msg);
}else {
server.sendMsg("["+ this.clientName +"]对你们说:"+msg);
}
}
}
}
@Override
public void run() {
while(isRuning) {
String msg = receviceMsg();
sendMsgToAllClient(msg,false);
}
}
}
服务端调用代码不用变,这样就实现 私聊,客户端说话的时候带客户端用户名啦!
效果示例: