网络编程 客户端实现登录 私聊和群聊
内容
1.建立多个客户端
2.向某一个客户端发起私聊
3.实现客户端的群聊
必须客户端和服务器端有一个规范
- 客户端的需求可以在发送的字符里面体现
1.登录 u+ 姓名 u+
2.返回结果 成功1 失败-1
3.私聊 p+ 姓名 内容 p+
4.群聊 群聊不加任何符号 一发消息就显示在公屏里每个人可见
代码
- 定义一个接口,确定一套规范
public interface ChatProtocol {
// 登录
String LOGIN_FLAG = "u+";
// 私聊
String PRIVATE_FLAG = "p+";
// 群聊
String PUBLIC_FLAG = "a+";
// 分隔符
String SPLIT_FLAG = "♥";
// 成功的状态
String SUCCESS = "1";
String FAILURE = "-1";
}
- 定义UserManager类 管理所有登录用的信息
/**
* 管理所有的登录的用户 Map>
* 判断某个用户是否已经登录
*/
public class UserManager {
// 保存所有用户信息
private Map 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;
}
/**
* 获取所有人的socket对象
*/
public synchronized Collection allUsers(){
return users.values();
}
}
- Server类
主线程管理监听客户端的连接
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) {
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 name = line.substring(2,line.length()-2);
// 判断这个用户是否已经登录
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)){
// p+jack♥hellop+
// 获取信息
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 {
//群聊
//处理数据
String msg = line.substring(2,line.length()-2);
// 获取当前用户的名称
String currentName = Server.manager.nameBySocket(socket);
// 遍历所有的用户信息
Collection sockets = Server.manager.allUsers();
for(Socket s:sockets){
PrintStream temps = new PrintStream(s.getOutputStream());
temps.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;
try(Socket socket = new Socket("10.129.28.234",8888)) {
ps = new PrintStream(socket.getOutputStream());
brServer = new BufferedReader(new InputStreamReader(socket.getInputStream()));
br = new BufferedReader(new InputStreamReader(System.in));
// 登录
while (true){
// 接收终端输入信息
// BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 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) {
System.out.println("网络出错!");
}finally {
try {
if (br!=null) {
br.close();
}
if (socket != null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
运行结果
心得
今天写这个demo,一开始还能跟上,到后面就跟不上了,出了一些bug。不过还是能够懂大概的过程。后面自己按照自己的理解重新将代码推敲了一遍。总算是找出了出错的地方。修改了之后已经没问题了。自己也将代码重写了一遍,不过还是有些地方比较模糊,还是看了原代码。虽然并不能自己独立写出,不过我还是蛮高兴的。