通信之增强版服务器
程序员文章站
2022-06-01 13:20:53
...
要做通信,当然不能停留在仅满足于实现它,就算我们一时还做不出像腾讯那样强大的qq,但至少我们可以以之为目标并一步一步做下去。
我们暂且还用命令行的telnet命令充当客户端,那么,就服务器而言, 在服务器的最简代码基础上,我们可添加的内容还有很多。
最基本的,不能只发字符而不能发送汉字吧;其次,服务器不能只可以连一个客户端吧;然后,客户端是不是要有用户名和密码才能登录呢;至于聊天,客户端之间要可以群聊吧,服务器要可以给每一个客户端发公告吧;最后的最后,是不是应该给服务器加个界面美化一下呢?
这些功能,虽然看起来还不及qq的万分之一,但如果连这些最基础的模块都没有,如何一步“登上”qq呢?不要去问:以这样的速度什么时候才能做出来山寨qq。这个问题并没有答案,但肯定的是,不是今天,也不是明天。
那么,现在,就让我们实现这个增强版的服务器。这里我们定义5个类。
ChatUI:实现服务器界面并启动服务器。
ChatThread:处理服务器对象的线程类,每一个ChatThread对象对应一个客户机。
ChatTools:将某个客户机发来的消息发送给其他客户机。
DaoTools:生成模拟数据,验证客户端账号。
UserInfo:用户数据类,每个UserInfo对象存放一个用户的账号。
以下解释几个主要方法。
首先是用户名验证,我们只简单的验证用户名是否存在,用户名是我们预先存入数据库的:
//验证是否存在该用户名 public static boolean checkLogin(UserInfo user){ if(userDB.containsKey(user.getName())) return true; System.out.println("认证失败"+user.getName()); return false; } //内存用户信息数据库 private static Map<String, UserInfo> userDB = new HashMap(); //静态块:模拟生成内存中的用户数据,用户名为user1~10 //当程序启动时,这段代码(静态块中的)会自动执行,向userDB中存放数据 static{ for(int i=0;i<10;i++){ UserInfo user = new UserInfo(); user.setName("user"+i); user.setPassword("password"+i); userDB.put(user.getName(), user); } }然后是发送群聊消息的方法,我们分为两种,一种是客户端给其他客户端发送的消息,一种是服务器给所有客户端发送的消息,(sendMsg与最简代码发送消息的类似):
public static void castMsg(UserInfo sender,String msg){
msg = sender.getName()+" say:"+msg;
for(int i=0;i<stlist.size();i++){
ChatThread ctt = stlist.get(i);
//如果客户端的port与自身不同,才发送消息
if(ctt.getClient() !=sender.getClient()){
ctt.sendMsg(msg);
}
}
}
public static void castMsg(String msg){
for(int i=0;i<stlist.size();i++){
ChatThread ctt = stlist.get(i);
ctt.sendMsg(msg);
}
}
最后,在线程run()方法中读取客户机发来的消息(closeMe是关闭连接的方法):
InputStream ins=client.getInputStream();
out=client.getOutputStream();
//将输入流ins封装为可以读取一行字符串,也就是以\r\n结尾的字符串
BufferedReader brd = new BufferedReader(new InputStreamReader(ins));
sendMsg("欢迎你来聊天!请输入你的用户名:");
String userName = brd.readLine();
sendMsg(userName+" 请输入你的密码:");
String password = brd.readLine();
user = new UserInfo(client);
user.setName(userName);
user.setPassword(password);
//调用数据库模块,验证用户是否存在
boolean loginState = DaoTools.checkLogin(user);
if(!loginState){//不存在这个用户账号则关闭
this.closeMe();
return ;
}
ChatTools.addClient(this); //认证成功:将这个对象加入服务器队列
String input = brd.readLine();//一行一行的读取客户机发来的消息
if(!"bye".equals(input)){//一直读取
System.out.println("服务器收到的是: "+input);
if(runFlag){
//读到一条消息后,就发送给其他的客户机去...
ChatTools.castMsg(this.user, input);
input = brd.readLine();//读取下一条
}
}
if("bye".equals(input)){
if(runFlag)
ChatTools.castMsg(this.user, "我下线了,再见!");
this.closeMe();
}
最基本的模块大概就是这样,只要把它们结合起来,就可以实现增强版的服务器了。