续上文:
现在服务器已经的到了客户端发来的信息了,但是存在一个问题。我现在服务器里只有消息发送者这一个线程存在,接受者并没有线程。所以需要在每个用户登录的时候就新建一个客户端连接到服务器的线程。
回到server类的验证用户登录中,只要验证成功,就新建一个这样的线程。
if (u.getpassword().equals(123)) {
m.setmstype(1);
oos.writeobject(m);
// 单开一个与客户端连接的线程
servertoclientthread stct = new servertoclientthread(s);
但是建立好的线程放到哪里?才能在需要的时候就拿出来用呢?我们需要一个统一存放和管理servertoclientthread线程的类,即一个hashmap。新建一个managerclientthread类。
publicclass managerclientthread {
为了方便以后直接访问,并且该哈希表建立好后,就只有一张,不会增加和消失,于是用static修饰。key值就用string类的登录人id表示,具体存放的则是servertoclientthread线程。
publicstatichashmaphm = new hashmap();
新建一个add方法
// 向hm中添加客户端通讯线程
publicstaticvoid addclientthread(string uid, servertoclientthread ct) {
hm.put(uid, ct);
}
再新建一个getter方法
publicstatic servertoclientthread getclientthread(string uid) {
return (servertoclientthread) hm.get(uid);
}
至此,managerclientthread类的所有方法全部定义完成。我们就可以回到server类中,在建立好一个servertoclientthread后,把该线程存到hashmap中去。然后启动该线程。
managerclientthread.addclientthread(u.getuserid(), stct);
stct.start();
至此,从客户端到服务器的第一条线已经搭建完毕。下面需要从服务器识别消息的发送和接受者,再发给对应的客户端。所以先回到servertoclientthread类,继续实现服务器的转发。
//转发
首先需要从managerclientthread中通过message中的getter属性取得相应的线程。
servertoclientthread sc = managerclientthread.getclientthread(m.getgetter());
再把该线程的socket的io流中的输出流获取到,把message对象传给这个流中。
objectoutputstream oos = new objectoutputstream(sc.s.getoutputstream());
oos.writeobject(m);
该oos流中的message就是用户a想要发送给用户b的消息。现在假设我们登录了用户b,该如何得到该消息呢?首先当然是用一个ois.read方法读内容并转化为message。但是假设用户b同时接收到了用户a和用户c发来的信息,如果一个线程,那么b在读取了a发来的message以后就不能再读取c发来的message了,所以这里要使用多线程。新建一个clienttoserverthread类。
publicclass clienttoserverthread extends thread {
private socket s;
public socket gets() {
return s;
}
publicvoid sets(socket s) {
this.s = s;
}
public clienttoserverthread(socket s) {
this.s = s;
}
重写线程里的run方法。
publicvoid run() {
while (true) {
objectinputstream ois;
try {
获取s中的流即刚刚传给服务器的oos流中的message。
ois = new objectinputstream(s.getinputstream());
message m = (message) ois.readobject();
system.out.println(读取到服务器发来的消息 + m.getsender() + 给
+ m.getgetter() + 内容 + m.getcon());
// 把从服务器得到的消息显示到该显示的聊天界面
chat chat = managerchat.getchat(m.getgetter() +
+ m.getsender());
chat.showmessage(m);
} catch (exception e) {
// todo auto-generated catch block
e.printstacktrace();
}
}
由上可见,我们分辨的不是流中的特征,而是新开启一个可以分辨的chat类的对象,这样可以直接将message分配给chat。所以新建一个managerchat类来管理chat对象。
publicclass managerchat {
privatestatichashmaphm = new hashmap();
//加入
publicstaticvoid addchat(string loginidandfriendid,chat chat){
hm.put(loginidandfriendid, chat);
}
//取出
publicstatic chat getchat(string loginidandfriendid){
return (chat)hm.get(loginidandfriendid);
}
}
同样使用hashmap的模式。key值定义为登录id+聊天对象id。所以在friendlist类里,双击好友头像后的方法里要添加一句。
managerchat.addchat(this.ownerid+ +friendnum, chat);
把该chat对象存到managerchat里的hashmap中去。在clienttoserverthread的run 方法中就可以得到该chat,把读取到的message内容传给chat中的showmessage方法。
在chat中写一个showmessage方法:
publicvoid showmessage(message m) {
string info = m.getsender() + 对 + m.getgetter() + 说 + m.getcon()
+ \;
}
而最开始我们定义专门连接的类connect,就需要专门来启动该线程,启动的时间就是用户登录验证成功以后,所以在验证登录message的type为1时,就启动该线程。
// 创建一个该qq和服务器连接的通讯线程
clienttoserverthread ccst = new clienttoserverthread(s);
// 启动该通信线程
ccst.start();
managerclienttoserverthread.addclienttoserverthread(
((user) o).getuserid(), ccst);
我们做clienttoserverthread的目的就是让一个用户同时和多个用户聊天,所以还需要一个managerclienttoserverthread类来管理该线程。
o'di
这样每一个用户都有自己单独的一个线程去与服务器取得联系,并且该线程可以读取服务器发来的信息并提取出发送者和接受者,从hashmap中提出一个符合的chat对象,并让chat对象显示出消息。
java学习交流,资源分享可关注小编头条号,点击微头条或者私信发 java获取!欢迎私信小编。
【私信方法】文章上方处点击“作者头像”,进入作者首页,在作者主页上方点击“ 关注” 旁边的 “发私信” 即可。
最后的流程图和类之间的关系:
【微信 、编程语言、java、互联网、程序员】