目的
通过之前学习了Java语言中的网络编程,今天就来实现QQ内部的相应聊天功能(群聊、登录功能、群聊)
相关技术、及其使用
1、通过创建一个接口对客户端和发服务器端进行进行相应的规范
客户端的需求可以再发送的字符里面体现
1、登录 u+姓名 u+
2、返回结果 成功1 失败-1
3、私聊 p+姓名 ♥ 聊天内容 p+
4、群聊 a+聊天内容 a+
5、发文件 f+
6、发语音 v+
public interface ChatProtocol {
//登录
String LOGIN_FLAG = "u+";
//私聊
String PRIVATE_FLAG = "p+";
//群聊
String PUBLIC_FLAG = "a+";
//分隔符
String SPLIT_FLAG = "♥";
//成功与否的状态
String SUCCESS = "1";
String FAILUER = "-1";
}
2、创建服务器端和服务器端的子线程
这个功能的代码在之前就有讲解,所以,在此就不详细讲解:
创建服务器端:
public class Server {
//用于保存每一个用户对应的姓名和socket
public static UserManager manager = new UserManager();
public static void main(String [] agrs){
//创建ServerSocket
try {
ServerSocket ss = new ServerSocket(8888);
//监听所有来连接的客户端
while (true){
Socket socket = ss.accept();
//让子线程处理这个socket
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
其次,创建子线程继承于Thread并实现Thread里面的run方法
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 {
//得到对应的输入流对象
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.FAILUER);
}else {
//没有登录
// 保存当前登录的用户信息
Server.manager.save(name,socket);
//发送结果给客户端
ps.println(ChatProtocol.SUCCESS);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
在子线程socket里面需要注意的一点就是,从终端获取到名字过后需要判断是否该用户已经登录同时实现接口ChatProtocol
3、创建客户端
创建客户端的相关步骤和之前的都差不多,但是,这次在客户端里面需要对登录进行相关处理:
try {
Socket socket = new Socket("10.129.14.97",8888);
//接收终端的输入流
br = new BufferedReader(new InputStreamReader(System.in));
//接收服务器端的输出流
ps = new PrintStream(socket.getOutputStream());
//接收服务器端的输入流
brSever = new BufferedReader( new InputStreamReader(socket.getInputStream()));
//登录
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 = brSever.readLine();
//判断登录结果
if(result.equals(ChatProtocol.SUCCESS)){
break;
}else{
System.out.println("用户名已存在,请重新登录");
}
}
//登录成功
//开启线程处理服务器端的输入
new ClientThread(socket).start();
//接收终端输入 发送给服务器端
String line ;
while ((line = br.readLine()) != null){
ps.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
4、最后创建一个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;
}
/*
获取所有人的socket对象
*/
public Collection<Socket> allUsers(){
return users.values();
}
}
PS
今天讲的这个demo是对昨天网络编程相关知识的复习和进一步延伸。今天,课堂上用到了Map集合和HashMap里面的toString方法,一下子没想起来,然后上完课后,自己跟着思路重新写demo的时候才想起来Map集合的相关用法,所以,感觉现在几乎又把之前学的那些知识个忘掉了,学了这个忘了那个。