主要实现的技术点:
1 实现群聊功能
2实现私聊功能
3增加登录功能
实现方式:
采用cs架构,面向Socket编程,将聊天室分为服务器端和客户端,其中,服务器端负责从客户端接收消息并且分析消息判断消息是群发和私聊。并且根据群发和私聊将消息对应的发送。
服务器端代码如下:
package com.chat03;
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;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 其他客户必须等待
* @author jh
*
*/
/**
* 群聊
* @author jh
*
*/
public class Chat {
//private List<Channel> all=new ArrayList<Channel>();
private static CopyOnWriteArrayList<Channel> all=new CopyOnWriteArrayList<Channel>();
//private String name;
public static void main(String[] args) throws IOException {
System.out.println("-----server-------");
ServerSocket serverSocket=new ServerSocket(8877);
while(true) {
Socket client=serverSocket.accept();
System.out.println("一个客户端建立了链接");
Channel channel=new Channel(client);
all.add(channel);
new Thread(channel).start();
}
}
/**
* 内部类channel区分不同的客户端
* 内部类可以方便的调用外部方法
* @author jh
*
*/
static class Channel implements Runnable{
//收发消息
//释放资源
private DataInputStream dataInputStream=null;
private DataOutputStream dataOutputStream=null;
private Socket client=null;
private boolean isRunning=true;
private String name;
public Channel(Socket client) {
super();
this.client = client;
try {
dataInputStream=new DataInputStream(client.getInputStream());
dataOutputStream=new DataOutputStream(client.getOutputStream());
this.name=Receive();
this.Send("欢迎你的到来");//因为欢迎消息只发生在登陆的时候,所以写在构造方法里面
this.SendOthers(this.name+"来到了shsxt",true);//
} catch (IOException e) {
release();
}
}
/**
* Send发送消息给自己,
* @param meg
*/
private void Send(String meg) {
try {
this.dataOutputStream.writeUTF(meg);
this.dataOutputStream.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}//Send给不同的流发送消息
/**
* 给不同的客户端发送消息
* 使用Channel的遍历
* @return
*/
private String Receive() {
String meg=null;
try {
meg=dataInputStream.readUTF();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return meg;
}
/**
* 判断是否为私聊@xxx:meg开头
* @param meg
* @param sys判断是不是系统的消息,如果是系统消息不用发送this.name+"对所有人说"+meg
*/
public void SendOthers(String meg,boolean sys) {
boolean isPrivate=meg.startsWith("@");
if(isPrivate) {
int idx=meg.indexOf(":");
String toName=meg.substring(1,idx);
String megs=meg.substring(idx+1);
for(Channel c:all) {
if(c.name.equals(toName)) {
c.Send(this.name+" 悄悄地对你说: "+megs);
}
}
}
else if(sys) {
for(Channel c:all) {
if(c!=this) {
c.Send(meg);
}
}
}
else {
for(Channel c:all) {
if(c!=this) {
c.Send(this.name+" 对所有人说: " +meg);
}
}
}
}
/**
* releasse释放所有的资源
*/
private void release() {
SxtUtils.close(dataInputStream,dataInputStream,client);
this.isRunning=false;
all.remove(this);
SendOthers(this.name+"已经离开了聊天室", true);
}
@Override
public void run() {
while(isRunning) {
String meg=Receive();
if(!meg.equals(null)) {
SendOthers(meg,false);
}
}
}
}
}
客户端需要不停的接受和发送消息,因此我们使用多线程不停的收发消息
package com.chat03;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.net.UnknownHostException;
/**
* 群聊
* @author jh
*
*/
public class Client {
public static void main(String[] args) {
System.out.println("----Client----");
BufferedReader bReader=new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入用户名:");
String name = null;
try {
name=bReader.readLine();//接收用户名
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Socket client;
try {
client = new Socket("localhost",8877);//阻塞式接收客户端
new Thread(new Send(client,name)).start();//开启发送多线程
new Thread(new Receive(client)).start();//开启接收多线程
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Send端
package com.chat03;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
public class Send implements Runnable{
private DataOutputStream dos;
private Socket client;
private BufferedReader bReader;
private boolean isRunning;
private String name;
public Send(Socket client,String name) {
super();
this.client=client;
this.isRunning=true;
this.name=name;
bReader=new BufferedReader(new java.io.InputStreamReader(System.in));
try {
dos=new DataOutputStream(client.getOutputStream());
send(name);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
this.reasle();
}
}
@Override
public void run() {
// TODO Auto-generated method stub
while(isRunning) {
String meg=getStrFromConsle();
if(!meg.equals("")) {
send(meg);
}
}
}
public void send(String meg) {
try {
dos.writeUTF(meg);
dos.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void reasle() {
SxtUtils.close(client,bReader,dos);
isRunning=false;
}
public String getStrFromConsle() {
try {
return bReader.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
reasle();
return null;
}
}
}
package com.chat03;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.Socket;
public class Receive implements Runnable{
private Socket client;
private DataInputStream dis;
private boolean isRunning;
public Receive(Socket client) {
super();
this.client = client;
this.isRunning=true;
try {
dis=new DataInputStream(client.getInputStream());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
isRunning=false;
}
}
public void reasle() {
SxtUtils.close(client,dis);
isRunning=false;
}
public String receive() {
String meg=null;
try {
meg=dis.readUTF();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
isRunning=false;
}
return meg;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(isRunning) {
String string=null;
if((string=receive())!=null) {
System.out.println(string);
}
}
}
}