【Java】通讯的协议实现和界面展示
·
一,常见问题
二,解决方法
三,总结
一,常见问题
在之前实现控制台聊天时,我们主要解决了如何通过 @ 符号区分广播和私聊。但是我们在真正使用时不可能使用控制台,于是会有下面这些问题:
-
如何判断一个客户端连接是执行登录还是注册,如何确保服务器能准确记录每个用户的用户名并将其与 Socket 绑定。
-
如何将原本在控制台通过Scanner 获取的字符串,通过 Swing 窗体的按钮触发并发送出去。
于是我们需要设计一套基础的接口来实现一个简单协议。
二,解决方法
我们定义了一个接口 MassageType,通过简单的字节码来标记动作类型。
package Contect260130.sever;
public interface MassageType {
public static final byte LOGIN=2; // 登录请求
public static final byte REGISTER=3; // 注册请求
public static final byte SUCCESS=1; // 操作成功
public static final byte FALSE=0; // 操作失败
public static final byte CHAT=4; // 聊天消息
}
在服务器端的 ServerThread 中,编写了 chickMsg 方法。服务器会先读取一个字节的 action,如果是登录则比对 uMsg 中的密码,如果是注册则存入 uMsg。
public String chickMsg(InputStream is,OutputStream os,Map<String,String> uMsg) throws IOException {
while(true){
int action=is.read();
if(action==MassageType.LOGIN){
System.out.println("用户选择登录");
String name=readString(is);
String password=readString(is);
String pass=uMsg.get(name);
//判断用户是否存在且密码正确
if(pass==null||pass.equals(password)){
os.write(MassageType.FALSE);
os.flush();
}else {
os.write(MassageType.SUCCESS);
os.flush();
return name;
}
} else if (action==MassageType.REGISTER) {
//将新用户存入map
String name=readString(is);
String password=readString(is);
uMsg.put(name,password);
os.write(MassageType.SUCCESS);
os.flush();
return name;
}
}
}
在 CFrame 界面中,我们不再需要 Scanner来在控制台进行消息的输入,通过为“发送”按钮添加 ActionListener,直接从 JTextField 获取文本。
sendBtn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String sendMsg = sendText.getText();
try {
writeString(client.client.getOutputStream(),sendMsg);
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
});
当用户通过校验后,其用户名被存储在 ServerThread 的 id 变量中,并存入全局 map。 服务器的核心逻辑是循环读取消息并利用 split("@") 进行分发:
// ServerThread.java 的 run 方法核心片段
String[] strings = new String(newBytes, StandardCharsets.UTF_8).split("@");
want = strings[0];
if (!want.equals("-1")) {
for (Map.Entry<String, Socket> value : map.entrySet()) {
if (value.getKey().equals(want)) {
OutputStream outPut = value.getValue().getOutputStream();
String str = new String("Client" + id + ":"); // id 是发送者的用户名
outPut.write(str.getBytes());
outPut.write(strings[1].getBytes());
outPut.flush();
}
}
} else {
for (Map.Entry<String, Socket> value : map.entrySet()) {
if (value.getValue() != this.socket) {
OutputStream outPut = value.getValue().getOutputStream();
outPut.write(("Client" + id + ":" + strings[1]).getBytes());
outPut.flush();
}
}
}
三,总结
通过引入 MassageType 接口,我们成功建立了一套简单的通讯协议,解决了登录与注册区分问题。通过编写页面使得程序从枯燥的控制台输入进化到了图形化交互。
更多推荐




所有评论(0)