实现私聊

一、前言

本来,实现私聊和公聊是差不多的,只要再添加一个消息处理方法即可,可是这里为什么要把它单独拿出来成一篇呢?因为,我在这个过程中发现了两个重要的问题。是什么问题呢?我们先不说,先在上一篇的基础上实现私聊功能之后再慢慢揭露。

二、用户地址绑定错误问题

首先,ChatFrame 的按钮点击事件SendAction 的代码改成如下所示:

//定义发送消息按钮点击事件Action sendAction = new AbstractAction(){@Overridepublic void actionPerformed(ActionEvent e) {// TODO 自动生成的方法存根SocketAddress destAddress = user.getAddress();System.out.println("ChatFrame_destAddress="+destAddress);//公聊“用户”,其address是nullif(destAddress == null){System.out.println("destAddress == null");LoginFrame.comUtil.broadMsg(chatField.getText());}else{LoginFrame.comUtil.sendMsg(chatField.getText(), destAddress);}}   };

当我们发现是私聊消息时,就调用 LoginFrame.comUtil.sendMsg  方法。然后在消息处理类 MsgProcessor中增加一个私聊消息处理方法:

/*** 处理私聊消息* @param broaInPacket* @param friendListFrame*/public void processSingleMsg(DatagramPacket broaInPacket, FriendListFrame friendListFrame){try {String msg = new String(broaInPacket.getData(), 0, broaInPacket.getLength(),ComUtil.CHARSET);SocketAddress destAddress = broaInPacket.getSocketAddress();System.out.println("processSingleMsg_destAddress"+destAddress);User toUser = friendListFrame.findUserByAddress(destAddress);ChatFrame toChatFrame = toUser.getChatFrame();if(toChatFrame == null){toChatFrame = new ChatFrame(toUser); toUser.setChatFrame(toChatFrame);}if(!toChatFrame.isShowing()){toChatFrame.setVisible(true);}System.out.println("processSingleMsg_msg="+msg);toChatFrame.addMsg(toUser.getName()+" : "+msg);} catch (UnsupportedEncodingException e) {// TODO 自动生成的 catch 块e.printStackTrace();}}

最后,在通信类 ComUtil 中的 ReadSingle 线程方法加入

msgProcessor.processSingleMsg(singleInPacket, LoginFrame.friendListFrame);

看起来是没有问题的。我们运行一下看看:

本来,我们打开了一个私聊窗口,输入了 abc ,点击发送信息,可是这条信息却出现在公聊窗口中去了。这是为什么呢?我们在ChatFrame 的 sendAction 中打了日志:

ChatFrame_destAddress=/192.168.48.1:30000

接收到公聊消息=abc

问题就出在端口号 30000 上,用户私聊占用端口应该是 30001。这条私聊消息被发送到多点广播端口上去了,结果被处理公聊消息的线程处理了。那么,这个destAddress是怎么来的?SocketAddress destAddress = user.getAddress();也就是说,用户登录后绑定地址时绑定错了。这个过程在 MsgProcessor 中的processBroadMsg 方法处理用户上线时的逻辑里。

User user = new User(userInfo[0], userInfo[1], broaInPacket.getSocketAddress(),0);

这里是有问题的,broaInPacket.getSocketAddress() 得到的端口号是广播端口号30000 ,按照ComUtil中的约定,应该加1才对。修改之后:

InetSocketAddress srcAddress = (InetSocketAddress) broaInPacket.getSocketAddress();System.out.println("srcAddress="+srcAddress);SocketAddress theUserAddress = new InetSocketAddress(srcAddress.getHostString(), srcAddress.getPort()+1);User user = new User(userInfo[0], userInfo[1], theUserAddress,0);

这样应该就可以了。

三、多网络接口的问题

到目前为止,我们的程序已经可以完成收发消息的功能了。可是,当我将它打包放到局域网上另一台机器上运行的时候,它却并不能“发现”局域网上的其它用户。这时我想起来我用ipconfig命令在我本机查看时有多个ip地址。《疯狂java讲义》P803页也说过“在某些系统中,可能有多个网络接口。这可能会给多点广播带来问题,这时候程序需要在一个指定的网络接口上监听,通过调用setInterface() 方法可以强制MulticastSocket 使用特定的网络接口。”那么,问题就出在这里了。既然如此,那么我们干脆把所有ip列举出来,让用户自己选择。

新增一个 IPFinder 工具类:

package com.myipmsg.util;import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
import java.util.Vector;/*** 查询所有ip* @author ThinkPad**/
public class IPFinder {public static Vector<String> find(){Vector<String> ipList = new Vector<>();Enumeration<NetworkInterface> netInterfaces = null;  try {  netInterfaces = NetworkInterface.getNetworkInterfaces();  while (netInterfaces.hasMoreElements()) {  NetworkInterface ni = netInterfaces.nextElement();   Enumeration<InetAddress> ips = ni.getInetAddresses();  while (ips.hasMoreElements()) {  String ip = ips.nextElement().getHostAddress();if(!ip.contains(":") && !ip.equals("127.0.0.1")){ipList.add(ip);}}  }  } catch (Exception e) {  e.printStackTrace();  }  System.out.println(ipList);return ipList;}public static void main(String[] args) {// TODO 自动生成的方法存根find();}}

工程中其它地方的修改这里就不一一赘述了,有兴趣的可以去查看附件。修改之后的登录窗口:

好友列表中把用户的ip也一并显示出来了:

注:本来还有第五篇,写传输文件的,因为之前在自己局域网中测试发送文字信息时老是不成功,备受打击,所以索性没写了。那就不写了吧。代码在附件中都有。

所有代码可在此处下载:http://download.csdn.net/detail/zhutulang/9207885

一步一步写简易版飞鸽传书(四)相关推荐

  1. 1.一步一步写简易版飞鸽传书(一)

    基本窗体的设计 一.前言 注:本系列几篇文章展示了"简易版飞鸽传书"的编写过程,该程序可实现在局域网内收发文字信息和文件的功能.希望可以通过这个样例让读者对java网络编程和IO编 ...

  2. 一步一步写简易版飞鸽传书(二)

    通信类 ComUtil 的设计 一.前言 在本篇中,我们将介绍通信类的设计.这个类实现了发送.接收字符消息的方法,分别分为私聊消息和公聊消息.公聊就类似于QQ群聊一样,所有登录用户都能看到,而私聊则是 ...

  3. 一步一步写简易版飞鸽传书(三)

    实现公聊 一.前言 我们首先来回顾一下到目前为止我们已经完成的工作.我们已经完成登录窗口.好友列表窗口和聊天窗口以及一个通信类.当我们打开登录窗口,填好用户名选好头像之后,点登录按钮就会弹出一个好友列 ...

  4. java飞鸽传书_java简单版飞鸽传书

    [实例简介] 使用java实现的简单版飞鸽传书,可以单聊.群聊.发送文件,使用UPD获取在线用户及聊天,使用TCP发送文件.代码比较简洁,界面工整,学习使用. [实例截图] [核心代码] simple ...

  5. CentOS版飞鸽传书

    飞鸽传书 强大到如此地步,系统无所不垮,无所不容,真佩服原创的作者,有如此高深的功力,打造如此威力无比的软件. 即时通讯软件可谓应有尽有,作为开源的,飞鸽传书 的使用比较广,在各种平台上,都有相应的版 ...

  6. java版飞鸽传书源代码

    自己写的,基本实现了飞鸽传书的 大部分功能,支持断点续传,需要jdk1.6支持,在这里下载源码 http://download.csdn.net/source/219279

  7. 手机版飞鸽传书:无线牵

    [中文名]无线牵 [英文名]Wireless Linker [组成]PC端(PC版)WirelessLinker-PC.jar.Mobile端(手机版)WirelessLinker.jar [作者]火 ...

  8. 飞鸽传书每写一行代码都会有新的成就

    喜欢的人,日子过得非常开心,飞鸽传书每写一行代码都会有新的成就,尤其当自己的作品被广泛应用的时候,那种自豪感油然而起. 不喜欢的人,飞鸽传书x坐在电脑前极端无聊,被进度压得喘不过气来,天天为找bug改 ...

  9. 飞鸽传书2007绿色版

    各位哥哥转载请注明出处呀,要说明来自我的CSDN博客,谢谢,近工作比较忙,很少来CSDN,昨天一个朋友跟我说,他下载不了我写的< 飞鸽传书2007绿色版>,我觉得奇怪,于是上网一搜,果然没 ...

最新文章

  1. 0308-标签的用法(a,ul/ol,table)
  2. 特约专栏丨王耀南院士:人工智能赋能无人系统
  3. 如何在Power 750上实现硬盘背板的分离
  4. 单词数 (STL set集合)
  5. [转载] MFC绘制动态曲线,用双缓冲绘图技术防闪烁
  6. flex 单独一行_简述flex布局
  7. 网站日志统计查询工具
  8. 媒体查询Media Query
  9. 利用哈希表设计快速电话号码查询系统
  10. 微信HOOK发送Emoji表情
  11. OMNeT++学习---TicToc(1)
  12. 快速:通过画图了解Racket
  13. hibernate的关联映射 (员工管理)
  14. 安装Microsoft Office - Win系统
  15. Problem Q: 计算公司员工的工资
  16. AS 5637.1跟AS 3837是什么关系?
  17. Android开发最佳实践
  18. 深入了解 vue-cli
  19. 国际标准刊号(ISSN)
  20. micro-ROS之esp32与ros2资料(freertos)

热门文章

  1. JavaScript实现倒计时案例
  2. 我的世界服务器怎么修复武器,我的世界中怎么修复破损的剑/武器?
  3. 「笨鸟先飞」001-SpringWeb
  4. php7 部分 新特性
  5. MATLAB关闭科学计数法显示
  6. 微信小程序中使用echarts
  7. 小米、OPPO、vivo的“枪手博弈”,小米会先出局?
  8. python-pyglet游戏之minecraft远古版
  9. toggle,hasClass
  10. 表白神器——python,一“枪”一个准,限用一次!!(两次以上就无效了)