有了Command 接口,我们可以定义一些命令:
这些命令也代表了一些基本的需求
1. @pub 向聊天室中发广播消息
2. @quit 退出聊天室 , 如果断线,聊天室可以自动将与客户端的连接断开
3. @listmember 查看聊天室中的所有人
4. @login username password 以用户名和密码登陆服务器
5. @regist username password 注册用户
6. @usr username|socket address 向特定用户发消息
有了以上需求的话,我们就需要定义一些数据结构:
首先定义会员类:
package com.tcl.chat;
import java.lang.Thread.State;
/**
* 会员类
*
* @author tmdpzc
*
*/
public class Member {
private String mUsername;
private String mPassword;
private MemberState mState;
/**
* 定义会员的状态
* @author tmdpzc
*
*/
static class MemberState {
public static final int OFFLINE = 0;
public static final int UNLOGIN = 1;
public static final int ONLINE = 2;
public int state = 0;
public MemberState() {
// do nothing
}
public void setState(int state) {
this.state = state;
}
}
public boolean login(String username, String password) {
if (this.mUsername.equals(username) && this.mPassword.equals(password)) {
online();
return true;
}
return false;
}
public void connected(){
mState.setState(MemberState.UNLOGIN);
}
private void online() {
mState.setState(MemberState.ONLINE);
}
public void offline() {
mState.setState(MemberState.OFFLINE);
}
public Member(String username, String password) {
super();
this.mUsername = username;
this.mPassword = password;
this.mState = new MemberState();
}
public String getUsername() {
return mUsername;
}
public void setUsername(String username) {
this.mUsername = username;
}
public String getPassword() {
return mPassword;
}
public void setPassword(String password) {
this.mPassword = password;
}
}
定义一个存储会员的接口,可以理解为这是一个key-value 的数据库:
package com.tcl.chat;
public interface MemberStorage {
public boolean register(Member m);
public boolean has(String m);
public Member get(String name);
}
既然是简单的NIO 聊天室,就使用一个Map来存储Member的数据好了
一个实现MemberStorage接口的类
package com.tcl.chat.impl;
import java.util.HashMap;
import com.tcl.chat.Member;
import com.tcl.chat.MemberStorage;
public class MemberStorageImpl implements MemberStorage{
private HashMap<String, Member> mStorage;
public MemberStorageImpl(int size){
mStorage = new HashMap<String, Member>(size);
}
@Override
public boolean register(Member m) {
if (has(m.getUsername())) {
return false;
}else {
mStorage.put(m.getUsername(), m);
}
return true;
}
@Override
public boolean has(String name) {
Member m = mStorage.get(name);
if (m == null) {
return false;
}else {
return true;
}
}
@Override
public Member get(String name) {
return mStorage.get(name);
}
}
在ChatServer类中有这么几个Map:
Map<String, SocketChannel> mChannelMap;//socket address 到 SocketChannel的映射
Map<String, Member> mLoginMemberMap; //socket address 到 member的映射;
MemberStorage mMemberStorage; //所有会员的记录;
这些基础设施建立好了,后面就可以实现我们的命令了,也就是具体的功能。
首先是PubCmd:
package com.tcl.chat.command;
import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import com.tcl.chat.ChatServer;
public class PubCmd extends Command {
@Override
public void handleCmd(SelectionKey key, ChatServer server, String[] args)
throws IOException {
SocketChannel sc = (SocketChannel) key.channel();
StringBuilder sb = new StringBuilder();
if (args.length <= 1) {
return;
} else {
for (int i = 1; i < args.length; i++) {
sb.append(args[i]);
}
}
String pub_msg = sc.socket().getRemoteSocketAddress() + ": "
+ sb.toString();
System.out.println(pub_msg);
Iterator<SelectionKey> it = key.selector().keys().iterator();
while (it.hasNext()) {
SelectionKey sKey = (SelectionKey) it.next();
if ((sKey != key) && (sKey != server.getServerKey())) {
String address = ((SocketChannel) sKey.channel()).socket()
.getRemoteSocketAddress().toString();
if (server.getLoginMemberMap().get(address) == null) {
return;// 未登陆成功的终端看不到消息
}
if (sKey.attachment() == null) {
sKey.attach(pub_msg);
} else {
String at = (String) sKey.attachment();
sKey.attach(at + pub_msg);
}
sKey.interestOps(sKey.interestOps() | SelectionKey.OP_WRITE);
}
}
}
}
再来RegistCmd
package com.tcl.chat.command;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import com.tcl.chat.ChatServer;
import com.tcl.chat.Member;
import com.tcl.chat.utils.LogUtil;
public class RegistCmd extends Command {
private static ByteBuffer ERROR = ByteBuffer
.wrap("Error regist username and password".getBytes());
private static ByteBuffer SUCCESS = ByteBuffer.wrap("Regist success"
.getBytes());
@Override
public void handleCmd(SelectionKey key, ChatServer server, String[] args)
throws IOException {
// TODO Auto-generated method stub
LogUtil.i("Regist CMD :");
SocketChannel sc = (SocketChannel) key.channel();
LogUtil.e("args length " + args.length);
if (args.length == 3) {
String username = args[1];
String password = args[2];
Member mb = new Member(username, password);
boolean flag = server.getMemberStorage().register(mb);
if (flag) {
sc.write(SUCCESS);
SUCCESS.flip();
return;
}
}
sc.write(ERROR);
ERROR.flip();//要注意,ByteBuffer要 调用filp才能在第二次的时候重新发送
return;
}
}
分享到:
相关推荐
NULL 博文链接:https://tmdpzc.iteye.com/blog/1737928
用java nio写的一个完整的、可运行的聊天室程序;复制代码到项目后可直接运行。
2,运行client.bat启动客户端,可以打开编辑,ip,和端口号 3,自己发送的信息,自己是看不到的,运行多个客户端,其他的客户端可以看得到的 4,修改封装http做成短连接处理,就是一个小型的webserver,或者结合...
1.学习时的一个聊天室程序,将服务端改为NIO机制 2.支持多人同时在线局域网聊天 3.知识面:JSwing,NIO,消息包加密,解密,单列模式的线程安全机制等.
服务端程序基于javaNIO,客户端程序基于旧IO,读完<<javaNIO>>后,导入eclipse即可运行,支持多人在线聊天,上下线通知.PS:非GUI程序,毕竟javaSwing用的少,不懂的地方大家可以一起讨论,评论必回!
基于java tcp socket通信的拆包和装包源码 功能 1)编写一个 NIO 群聊系统,实现服务器端和客户端之间的数据简单通讯(非阻塞) 2)实现多人群聊 3)服务器端:可以监测用户上线,离线,并实现消息转发功能 4)客户端:...
ctrl + f5利用在http请求头中加入缓存控制:no-cache与Pargma:no-cache确保请求到前端缓存如Varnish代理缓存服务器。且ctrl + f5会避免请求浏览器自身缓存直接向目标网址发起请求DNS域名解析过程a)浏览器缓存b)...
java聊天室 2个目标文件,简单。 java模拟掷骰子2个 1个目标文件,输出演示。 java凭图游戏 一个目标文件,简单。 java求一个整数的因子 如题。 Java生成密钥的实例 1个目标文件 摘要:Java源码,算法相关,密钥 ...
服务器可以执行一个线程,运行Selector程序,进行监听操作。 新连接, 已经连接, 读取数据,写入数据 Selector常用方法: public static Selector Open(); 得到一个选择器对象 public int select(long time...
java聊天室 2个目标文件,简单。 java模拟掷骰子2个 1个目标文件,输出演示。 java凭图游戏 一个目标文件,简单。 java求一个整数的因子 如题。 Java生成密钥的实例 1个目标文件 摘要:Java源码,算法相关,密钥 ...
提供了本书第13章的JSP聊天室实例的源程序; \char15\15-1\ Java Applet HelloWorld 提供了本书第15章的Java Applet HelloWorld的源程序; \char15\15-2\ 双缓冲图像技术例子 提供了本书第15章的双缓冲图像...
NaiveNet它是基于NIO网络模型设计完成的网络通信组件,这套组件可以让我们HTML5,类别小程序/小游戏以长连接(Web Socket)通信模式开发应用,面向需求的高度封装开发者如果您想做一个实时交互应用程序一个实时的小...