Socket实现QQ群聊私聊功能
- 1.每个客户端一个名称
- 2.向某一个客户端发起私聊
- 3.群聊
- 客户端只能向服务器发送文件或者字符
- 服务器端只能得到客户端发过来的数据
- 必须客户端和服务器端有一个规范
- 客户端的需求可以在发送的字符里面体现
- 私聊 p+姓名 ♥ 聊天内容
- 群聊 a+ 聊天内容 a+
基本可以用这个图片来表示一下
首先定义规范
public interface ChatProtocol {
String LOGIN_FLAG="u+";
String PRIVAT_EFLAG="p+";
String PUNLIC_FLAG="a+";
String SPLIT_FLAG="♥";
String SUCCESS="1";
String FALIURE="-1";
}
注意是在接口里面定义的
定义一个管理的类 管理所有登录用的信息
管理所有的登录的用户Map<String,Socket>
public class UserManager {
//保存所有用户信息
private Map<String, Socket>users=new HashMap<>();
/**
* 判断用户是否已经登录
*/
public boolean isLogined(String name){
//遍历数组
for(String key:users.keySet()){
if (key.equals(name)){
return true;
}
}return false;
}
public void save(String name,Socket socket){
users.put(name,socket);
}
/**
* 通过用户名碰到对应的socket
*/
public Socket socketByName(String name){
return users.get(name);
}
/**
* 通过socket对象找到对应的名称
*/
public String nameBySocket(Socket socket){
for(String key: users.keySet()){
if(socket==users.get(key)){
return key;
}
}return null;
}
/**
*获取所有人的socket对象
*/
public synchronized Collection<Socket> allUsers(){
return users.values();
}
}
在Server类里面主线程管理的是监听客户端的连接,创建子线程用于每个客户端的输入输出
public class Server {
//用于保存每一个用户对应的姓名和socket
public static UserManager manager=new UserManager();
public static void main(String[] args){
try(ServerSocket ss=new ServerSocket(8888);) {
while(true){
Socket socket=ss.accept();
//让子线程处理这个socket
new ServerThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ServerThread extends Thread{
private Socket socket;
public ServerThread(Socket socket){
this.socket=socket;
}
@Override
public void run() {
BufferedReader br=null;
PrintStream ps=null;
try {
//登录
//1.得到对应的输入流对象
br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//得到对应的输出流
ps=new PrintStream(socket.getOutputStream());
String line=null;
while((line=br.readLine())!=null){
if (line.startsWith(ChatProtocol.LOGIN_FLAG)&&line.endsWith(ChatProtocol.LOGIN_FLAG)){
//String[] items=line.substring(2).split("u+");
//String name=items[0];
//获取名字
String name=line.substring(2,line.length()-2);
//
if (Server.manager.isLogined(name)){
//登录过了
ps.println(ChatProtocol.FALIURE);
}else{
//没有登录
//保存当前登录的用户信息
Server.manager.save(name,socket);
ps.println(ChatProtocol.SUCCESS);
}
}//判断是不是私聊
else if (line.startsWith(ChatProtocol.PRIVAT_EFLAG)&&line.endsWith(ChatProtocol.PRIVAT_EFLAG)){
//获取信息
int endindex=line.length()-2;
String msg=line.substring(2,endindex);
//分割
String[] items=msg.split(ChatProtocol.SPLIT_FLAG);
//用户名
String name=items[0];
//聊天内容
String message=items[1];
//通过用户名找到对应的socket
Socket dessocket=Server.manager.socketByName(name);
PrintStream desPs=new PrintStream(dessocket.getOutputStream());
//获取当前用户的名称
String currentName =Server.manager.nameBySocket(socket);
//发送私聊信息
desPs.println(currentName+"向你发来私聊"+message);
}else{
//群聊
//处理数据
int endindex = line.length() - 2;
String msg=line.substring(2,endindex);
//获取当前用户的名称
String currentName=Server.manager.nameBySocket(socket);
//遍历所有的用户信息
Collection<Socket> sockets=Server.manager.allUsers();
for(Socket s:sockets){
PrintStream tempps=new PrintStream(socket.getOutputStream());
tempps.println(currentName+"发来群聊"+msg);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
当然里面包括了如何实现私聊和群聊的功能。
接下来就是客户端
主线程接收终端输入 子线程接收服务器端输入
public class Client {
public static void main(String[] args){
BufferedReader br=null;
PrintStream ps=null;
BufferedReader brServer=null;
try (Socket socket=new Socket("10.22.216.58",8888)){
ps=new PrintStream(socket.getOutputStream());
br=new BufferedReader(new InputStreamReader(System.in));
brServer =new BufferedReader(new InputStreamReader(socket.getInputStream()));
while(true){
//接收终端输入信息
//
//String line=br.readLine();
String line= JOptionPane.showInputDialog("请输入用户名");
String loginstr=ChatProtocol.LOGIN_FLAG+line+ChatProtocol.LOGIN_FLAG;
ps.println(loginstr);
String result=brServer.readLine();
if (result.equals(ChatProtocol.SUCCESS)){
System.out.println("登录成功");
break;
}else{
System.out.println("用户名已存在,请重新登入");
}
}
new ClientThread(socket).start();
//登录成功
String line=null;
while((line=br.readLine())!=null){
ps.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ClientThread extends Thread{
private Socket socket;
public ClientThread(Socket socket){
this.socket=socket;
}
@Override
public void run() {
BufferedReader br=null;
try {
br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line=null;
while((line=br.readLine())!=null){
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("网络出错了");
}finally{
try
{
if(br!=null){
{
br.close();
}
if (socket!=null){
socket.close();
}
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
}