目的
运用网络实现QQ的部分功能
主要内容
1.实现私聊
2.实现群聊
具体内容
定义一套规范
用于体现不同的内容
在包下定义一个ChatProtocol类
实现的内容
- 1.登录 u+ 姓名 u+
- 2.返回结果 成功1 失败-1
- 3.私聊 p+ 姓名♥内容 p+
- 4.群聊 a+ 姓名♥内容 p+
public interface ChatProtocol {
//登录
String LOGIN_FLAG="u+";
//私聊
String PRIVATE_FLAG="p+";
//群聊
String PUBLIC_FLAG="a+";
//分隔符
String SPLIT_FLAG="♥";
//状态
String SUCCESS="1";
String FAILURE="-1";
}
1.实现私聊
定义一个UserManager类,管理所有登录用的信息
/**
* 判断某个用户是否已经登录
*/
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()){
//取出这个key对应的socket对象
if (socket==users.get(key)){
return key;
}
}
return null;
}
}
服务器端
public class Server {
//用于保存每一个用户对应的姓名和socket
public static UserManager manager=new UserManager();
public static void main(String[] args){
//创建serversocket
try(ServerSocket ss=new ServerSocket(8888)){
//监听所有的客户端
while (true){
Socket socket=ss.accept();
//让子线程处理socket
new ServerThread(socket).start();
}
}catch (IOException e){
}
}
}
子线程处理每个客户端的输入输出
class ServerThread extends Thread{
private Socket socket;
public ServerThread(Socket socket){
this.socket=socket;
}
@Override
public void run() {
}
}
重写一个run方法,在run方法里面实现私聊
BufferedReader br=null;
PrintStream ps=null;
try {
//得到对应的输入流
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)){
//获取名字
//判断这个用户是否已经登录
if (Server.manager.isLogined(name)){
//登录过了,发送给客户端
ps.println(ChatProtocol.FAILURE);
}else{
//没有登录过
//保存当前登录的用户信息
Server.manager.save(name,socket);
//发送给客户端
ps.println(ChatProtocol.SUCCESS);
}
}
//判断是不是私聊
else if (line.startsWith(ChatProtocol.PRIVATE_FLAG)&&line.endsWith(ChatProtocol.PRIVATE_FLAG)){
//获取信息
String msg=line.substring(2,line.length()-2);
//分割
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{
//群聊
}
}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("127.0.0.1",8888)) {
//登录
//接收终端输入流
br=new BufferedReader(new InputStreamReader(System.in));
//发给服务器端的输出流
ps=new PrintStream(socket.getOutputStream());
//接收服务器端的输入流
brServer=new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true){
//接收终端输入
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;
while ((line=br.readLine())!=null){
//发送给服务器
ps.println(line);
}
} catch (IOException e) {
}
}
}
子线程
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){
System.out.println("网络出错");
}finally {
try {
if (br!=null) {
br.close();
}
if (socket!=null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
再创建一个客户端,实现在一台电脑上私聊
class Client1 {
public static void main(String[] args) {
BufferedReader br = null;
PrintStream ps = null;
BufferedReader brServer = null;
//连接服务器
try (Socket socket = new Socket("127.0.0.1", 8888)) {
//登录
//接收终端输入流
br = new BufferedReader(new InputStreamReader(System.in));
//发给服务器端的输出流
ps = new PrintStream(socket.getOutputStream());
//发给服务器端的输入流
brServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
//接收终端输入
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) {
}
}
}
2.实现群聊
在UsersManager里加allUsers方法
* 获取所有人的socket对象
public synchronized Collection<Socket> allUsers(){
return users.values();
}
在服务器端的不是私聊的else里加
//群聊
//处理数据
String msg=line.substring(2,line.length()-2);
//获取当前用户的名称
String currentName=Server.manager.nameBySocket(socket);
//遍历用户所有的信息
Collection<Socket> sockets=Server.manager.allUsers();
for (Socket s:sockets){
PrintStream tempps=new PrintStream(s.getOutputStream());
tempps.println(currentName+"发来群聊:"+msg);
若想在一台电脑上实现群聊,则可以添加多个客户端