关于通信的一些总结

OnlyChat通信遇到的问题小结:

 

客户端之间通信(单聊)

 

客户端1发送消息给客户端2,结果最后的结果是客户端1又收到了自己发送的消息,造成这种现象的原因:

解决上述问题前谈谈我发送消息的机制:客户端1与客户端2进行聊天,服务器端的处理线程Server_Thread先调用客户端1ServerSocket(线程连接对象)读取客户端1发来的消息,

然后,服务器调用客户端2的服务器连接线程(Server_Thread),之后就调用发送消息的方法将消息发送出去。

 

之所以,客户端1收到自己发送的消息是因为:虽然,调用的是客户端2的服务器端处理线程将消息发送给客户端2的客户端,但在发送消息的时候,却用的客户端1的数据输出流DataOutputStream对象,所以客户端1充当收发消息的角色。

 

<!--[if !supportLists]-->2.<!--[endif]-->多个客户端给同一个客户端发送消息遇到的问题

 

假如:客户端2,客户端3给客户端1发送消息

现象:只要是单纯的客户端2或者是客户端3与客户端1互发消息是没有问题的,但是当客户端2,与客户端1同时存在并且是给客户端1发送消息这是就出现了问题,客户端2,客户端3发消息给客户端1客户端1收到消息同时弹出多个聊天框。

分析:消息聊天框弹出机制:客户端1与客户端2聊天,当客户端2不存在的时候就实例化一个客户端2的聊天窗体,并且把该聊天窗体加入到自己的聊天窗体队列中。

看下产生上述现象的代码

 

 

 MsgOnly_Chat onlyChat = (MsgOnly_Chat)mHead;//单聊的消息对象

 

//得到保存聊天界面的链

List<ChatUI> chaList = getChatList();

         Int len = chaList.size();

If(len == 0){

                LogHelper.true_Info(MainUI.class    "!-----+++聊天窗体不存在。。。");

UserInfo myInfo = this.myInfomation(onlyChat.getFrom_User());//显示到聊天窗体的我的信息

//实例化聊天窗体(我的登录信息,客户端对象)

ChatUI cUI = new ChatUI(this.getuByMyself(),this.getClient());

//将实例化的界面添加到聊天界面的链表中

cUI.setNodeAccount(onlyChat.getFrom_User());//对方的聊天窗体有我的账号

this.addChatUI(cUI);

cUI.chatGUI(myInfo);

cUI.getShow_cont().append(msg);//显示聊天的消息

}Else If(len > 0){

For(int i=0;i<len;i++){

if(chaList.get(i).getNodeAccount() == onlyChat.getFrom_User() )

chaList.get(i).getShow_cont().append(msg);

 

}else{

//上述聊天窗体不存在的方法一致

}

}

分析原因:客户端2与客户端1发消息时,这时客户端1的聊天窗体的队列中已经有连个聊天窗体了(客户端1对客户端2(先),客户端1对客户端3(后)),所以毋庸置疑客户端1聊天队列chaList.get(0)==2的聊天窗口,chaList.get(1)只能是3的聊天窗口,从每次执行循环看,都是从0开始,所以每次判断信息的时候得到总是2的聊天窗口,所以3的聊天窗口每次都不存在,所以客户端3给客户端1发消息时,对于客户端1来说3的聊天窗体都是不存在的所以每发一条消息都要创建一个基于客户端13聊天窗体,如果是4个,5个,甚至更多个客户端与同一个客户端通信遇到问题都是一样的

解决问题:判断聊天窗体存在与否,就是要遍历整个客户端的聊天窗体,如果该聊天窗体对应的账号(用户登录账号,标识不同聊天窗体)与消息发送方的账号不一致,就实例化窗体,反之,直接把消息显示到已经存在的窗体上即可。

代码:

//查找聊天窗链表,判断聊天窗体是否存在

public int seekList(List<ChatUI> list, int account){

for(int i = 0; i < list.size(); i++){

if(list.get(i).getNodeAccount() == account)

return i;

}

return -1;

}

 

//得到保存聊天界面的链表

List<ChatUI> chaList = getChatList();

LogHelper.true_Info(MainUI.class"保存聊天窗体的队列:::"+chaList.size()+" 客户端窗体主界面的ID:"+this.getMainAccount());

 

    int index = this.seekList(chaList, onlyChat.getFrom_User());//返回聊天窗体在队列中的位置

    if(index != -1){//窗体存在

    

    chaList.get(index).getShow_cont().append(msg);

    

      }else{

    

    LogHelper.true_Info(MainUI.class"!-----+++聊天窗体不存在。。。");

UserInfo myInfo = this.myInfomation(onlyChat.getFrom_User());//显示到聊天窗体的我的信息

//实例化聊天窗体(我的登录信息,客户端对象)

ChatUI cUI = new ChatUI(this.getuByMyself(),this.getClient());

//将实例化的界面添加到聊天界面的链表中

cUI.setNodeAccount(onlyChat.getFrom_User());//对方的聊天窗体有我的账号

this.addChatUI(cUI);

cUI.chatGUI(myInfo);

cUI.getShow_cont().append(msg);//显示聊天的消息

    

}

 

<!--[if !supportLists]-->3.<!--[endif]-->就该练习的总结java中的封装

不多说封装是java的一个特征之一,封装有利于扩展性,便于修改代码,而且还有利于外部类的调用。。。

具体:

以写的搜索注册用户的界面为例:

搜索用户的界面组成:北边面板和南边面板组成,北边面板的主要功能是输入注册的用户的账号(账号可以模糊查询)查询出注册的用户的账号以及昵称显示到南边面板的表格中。。。很明显,按照程序的执行流程以及逻辑思路,我们的搜索界面先实例化了,而南面面板要显示的注册用户的数据必须要等到点击搜索按钮才能得到。。。此时怎么解决这个问题呢?当然你可能会想到在点击搜索按钮后再实例化一次搜索界面然后将得到的数据显示到南边面板的表格中就可以了。。。

这样做也是一种解决办法,但我认为不可行,加入说你的项目中出现了多个这样的情形,无意耗费了很多内存空间,这样你的程序也会报错。

解决办法:我想的是南边面板封装成为一个方法,第一次实例化的时候该类对象不调用生成南边面板的方法,当点击搜索按钮的时候只需要将请求发送给服务器,服务器响应的时候返回了注册用户信息的队列。。。我的所有客户端响应都是在主界面(MainUI)中完成的,第一次打开搜索界面也是在该MainUI界面中完成的,所以只需拿到该类中搜索界面的对象后调用生成南边面板的方法,将注册用户数据作为参数,然后显示到南边面板即可。。。这样也就解决了一个对象多次实例化的问题。。。

 

 

 

 

这就是上述问题的截图,我只是从遇到的问题中分析了一下封装的好处。。。

 

 

 

猜你喜欢

转载自1498116590.iteye.com/blog/2080476