一步一步写简易版飞鸽传书(四)
实现私聊
一、前言
本来,实现私聊和公聊是差不多的,只要再添加一个消息处理方法即可,可是这里为什么要把它单独拿出来成一篇呢?因为,我在这个过程中发现了两个重要的问题。是什么问题呢?我们先不说,先在上一篇的基础上实现私聊功能之后再慢慢揭露。
二、用户地址绑定错误问题
首先,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.一步一步写简易版飞鸽传书(一)
基本窗体的设计 一.前言 注:本系列几篇文章展示了"简易版飞鸽传书"的编写过程,该程序可实现在局域网内收发文字信息和文件的功能.希望可以通过这个样例让读者对java网络编程和IO编 ...
- 一步一步写简易版飞鸽传书(二)
通信类 ComUtil 的设计 一.前言 在本篇中,我们将介绍通信类的设计.这个类实现了发送.接收字符消息的方法,分别分为私聊消息和公聊消息.公聊就类似于QQ群聊一样,所有登录用户都能看到,而私聊则是 ...
- 一步一步写简易版飞鸽传书(三)
实现公聊 一.前言 我们首先来回顾一下到目前为止我们已经完成的工作.我们已经完成登录窗口.好友列表窗口和聊天窗口以及一个通信类.当我们打开登录窗口,填好用户名选好头像之后,点登录按钮就会弹出一个好友列 ...
- java飞鸽传书_java简单版飞鸽传书
[实例简介] 使用java实现的简单版飞鸽传书,可以单聊.群聊.发送文件,使用UPD获取在线用户及聊天,使用TCP发送文件.代码比较简洁,界面工整,学习使用. [实例截图] [核心代码] simple ...
- CentOS版飞鸽传书
飞鸽传书 强大到如此地步,系统无所不垮,无所不容,真佩服原创的作者,有如此高深的功力,打造如此威力无比的软件. 即时通讯软件可谓应有尽有,作为开源的,飞鸽传书 的使用比较广,在各种平台上,都有相应的版 ...
- java版飞鸽传书源代码
自己写的,基本实现了飞鸽传书的 大部分功能,支持断点续传,需要jdk1.6支持,在这里下载源码 http://download.csdn.net/source/219279
- 手机版飞鸽传书:无线牵
[中文名]无线牵 [英文名]Wireless Linker [组成]PC端(PC版)WirelessLinker-PC.jar.Mobile端(手机版)WirelessLinker.jar [作者]火 ...
- 飞鸽传书每写一行代码都会有新的成就
喜欢的人,日子过得非常开心,飞鸽传书每写一行代码都会有新的成就,尤其当自己的作品被广泛应用的时候,那种自豪感油然而起. 不喜欢的人,飞鸽传书x坐在电脑前极端无聊,被进度压得喘不过气来,天天为找bug改 ...
- 飞鸽传书2007绿色版
各位哥哥转载请注明出处呀,要说明来自我的CSDN博客,谢谢,近工作比较忙,很少来CSDN,昨天一个朋友跟我说,他下载不了我写的< 飞鸽传书2007绿色版>,我觉得奇怪,于是上网一搜,果然没 ...
最新文章
- 0308-标签的用法(a,ul/ol,table)
- 特约专栏丨王耀南院士:人工智能赋能无人系统
- 如何在Power 750上实现硬盘背板的分离
- 单词数 (STL set集合)
- [转载] MFC绘制动态曲线,用双缓冲绘图技术防闪烁
- flex 单独一行_简述flex布局
- 网站日志统计查询工具
- 媒体查询Media Query
- 利用哈希表设计快速电话号码查询系统
- 微信HOOK发送Emoji表情
- OMNeT++学习---TicToc(1)
- 快速:通过画图了解Racket
- hibernate的关联映射 (员工管理)
- 安装Microsoft Office - Win系统
- Problem Q: 计算公司员工的工资
- AS 5637.1跟AS 3837是什么关系?
- Android开发最佳实践
- 深入了解 vue-cli
- 国际标准刊号(ISSN)
- micro-ROS之esp32与ros2资料(freertos)