通信类 ComUtil 的设计

一、前言

在本篇中,我们将介绍通信类的设计。这个类实现了发送、接收字符消息的方法,分别分为私聊消息和公聊消息。公聊就类似于QQ群聊一样,所有登录用户都能看到,而私聊则是点开一个好友聊天窗口,只能聊天双方才能看到。我们暂时把这个类叫做 ComUtil 。

二、UDP协议

首先,我们来介绍下UDP协议(这部分内容摘自李刚《疯狂java讲义》第三版P798  17.4基于UDP协议的网络编程)。

UDP协议是一种不可靠的网络协议,它在通信实例的两端各建立一个Socket ,但这两个Socket之间并没有虚拟链路,这两个Socket只是发送、接收数据报的对象。Java提供了DatagramSocket对象作为基于UDP协议的Socket,使用DatagramPacket代表DatagramSocket发送、接收的数据。

下面来看看DatagramPacket的构造器:

①DatagramPacket(byte[] buf, int length) : 以一个空数组来创建DatagramPacket对象,该对象的作用是接收DatagramSocket中的数据。

②DatagramPacket(byte[] buf, int length, InetAddress addr, int port): 以一个包含数据的数组来创建DatagramPacket 对象,并且指定了IP地址和端口—决定了该数据报的目的地。

③DatagramPacket(byte[] buf, int offset, int length): 以一个空数组来创建DatagramPacket对象,并指定接收到的数据放入buf数组中时从offset开始,最多放length个字节。

④DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port): 创建一个用于发送的DatagramPacket对象,指定发送buf数组中从offset开始,总共length个字节。

从以上的描述中我们可以总结出这么几点:第一,DatagramPacket 用来表示发送、接收的数据。第二,如果我们要发送数据,那么需要指定数据报的地址(IP和端口),那么就应该使用上面的②号和④号构造器。第三,如果我们要接收数据,那么无需指定地址,那么就可以使用上面的①号和③号构造器。

另外,我们用 DatagramSocket 的 send(DatagramPacket p) 和 receive(DatagramPacket p) 方法来发送和接收数据报。

三、多点广播和MulticastSocket

现在,我们还有一个待解决的问题是:如何实现公聊?可以想象,任何一个用户发送了一条公聊消息后,我们必须要把这条消息发送给所有的用户。通常的思路是,用一个集合来保存所有的登录用户,每当一个用户发送了一条公聊消息,就将该消息发送给这个集合中的所有用户。但是,我们要注意去及时刷新这个用户集合,因为不断会有用户下线。幸好,现在有更好的解决方案。Java为UDP协议提供了 MulticastSocket 类,这个类可以将数据报以广播的方式发送到多个客户端。这就是所谓的多点广播。

若要使用多点广播,则需要让一个数据报标有一组目标主机地址,当数据报发出后,整个组的所有主机都能收到该数据报。IP多点广播(或多点发送)实现了将单一信息发送到多个接收者的广播,其思想是设置一组特殊网络地址作为多点广播地址,每一个多点广播地址都被看做一个组,当客户端需要发送、接收广播信息时,加入该组即可。IP协议为多点广播提供了这批特殊的IP地址,这些IP地址的范围是 224.0.0.0 至 239.255.255.255 。(《疯狂java讲义》)

MulticastSocket  有三个构造器:

①MulticastSocket(): 使用本机默认地址、随机端口来创建

②MulticastSocket(int portNumber): 使用本机默认地址、指定端口来创建

③MulticastSocket(SocketAddress bindaddr): 使用本机指定IP地址、指定端口来创建

MulticastSocket  使用joinGroup(InetAddress multicastAddr) 方法加入指定组,使用leaveGroup(InetAddress multicastAddr) 方法脱离一个组。

四、ComUtil设计

ComUtil的源码如下,有几个地方稍微解释下。我们定义了一个multicastSocket, 同时定义了DatagramPacket broadOutPacket 用于发送广播消息,DatagramPacket broaInPacket 用于接收广播消息。在ComUtil的构造器中,实例化broadOutPacket 指定了IP和端口号,而broaInPacket 则没有。这符合我们之前总结的结论。

同样的,我们定义了DatagramSocket singleDatagramSocket ,用DatagramPacket singleOutPacket 发送私聊消息,用DatagramPacket singleInPacket 接收私聊消息。如果你细心你就会发现,在ComUtil的构造器中,我们实例化singleOutPacket 时并没有指定IP和端口,可是它是用来发送消息的啊,怎么没指定“目的地”呢。原来,我们在发送私聊消息方法 public void sendMsg(String msg, SocketAddress socketAddress)中,才指定了它的目的地。因为我们实际上是提前在ComUtil的构造器中实例化了singleOutPacket ,而这时,我们并不知道谁会使用这个singleOutPacket 发送消息给谁。

另外,我们定义了两个线程分别不断读取公聊消息和私聊消息。Main测试方法说明这个类可以工作。

package com.myipmsg.comutil;import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.SocketAddress;
import java.net.UnknownHostException;/*** 通信类* @author ThinkPad**/
public class ComUtil {//字符编码private static final String CHARSET = "utf-8";//多点广播ipprivate static final String BROADCAST_IP = "230.0.0.1";//多点广播端口号private static final int    BROADCAST_PORT = 30000;//一次发送、接收数据包的长度private static final int DATA_LEN = 4096;//多点广播socketprivate MulticastSocket multicastSocket;//发送多点广播消息的DatagramPacketprivate DatagramPacket broadOutPacket;    //接收多点广播消息的DatagramPacketprivate DatagramPacket broaInPacket;//私聊socketprivate DatagramSocket singleDatagramSocket;//发送私聊消息的DatagramPacketprivate DatagramPacket singleOutPacket;//接收私聊消息的DatagramPacketprivate DatagramPacket singleInPacket;//构造器public ComUtil(){try {//多点广播InetAddressInetAddress broadcastAddress = InetAddress.getByName(BROADCAST_IP);// 初始化多点广播multicastSocketmulticastSocket = new MulticastSocket(BROADCAST_PORT);//将multicastSocket加入指定的多点广播地址multicastSocket.joinGroup(broadcastAddress);//设置本multicastSocket发送的数据包被回送到自身multicastSocket.setLoopbackMode(false);//初始化broadOutPacketbroadOutPacket = new DatagramPacket(new byte[0], 0, broadcastAddress, BROADCAST_PORT);//初始化 broaInPacketbroaInPacket = new DatagramPacket(new byte[DATA_LEN], DATA_LEN);//初始化私聊socketsingleDatagramSocket = new DatagramSocket(BROADCAST_PORT+1);  //占用端口是多点广播端口号加1//初始化singleOutPacketsingleOutPacket = new DatagramPacket(new byte[0], 0);//初始化singleInPacketsingleInPacket = new DatagramPacket(new byte[DATA_LEN], DATA_LEN);//开启读取多点广播消息的线程new ReadBroard().start();//开启读取私聊消息的线程new ReadSingle().start();} catch (UnknownHostException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}//广播消息public void broadMsg(String msg){byte[] msgByte;try {msgByte = msg.getBytes(CHARSET);broadOutPacket.setData(msg.getBytes(CHARSET));multicastSocket.send(broadOutPacket);} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}      }//不断读取多点广播消息的线程class ReadBroard extends Thread{public void run(){while(true){try {multicastSocket.receive(broaInPacket); System.out.println("接收到公聊消息="+ new String(broaInPacket.getData(), 0, broaInPacket.getLength(), CHARSET));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}/*** 发送私聊消息* @param msg*/public void sendMsg(String msg, SocketAddress socketAddress){try {singleOutPacket.setSocketAddress(socketAddress);singleOutPacket.setData(msg.getBytes(CHARSET));singleDatagramSocket.send(singleOutPacket);} catch (UnknownHostException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}    }//不断读取私聊消息的线程class ReadSingle extends Thread{public void run(){while(true){try {singleDatagramSocket.receive(singleInPacket);System.out.println("接收到私聊信息="+new String(singleInPacket.getData(), 0, singleInPacket.getLength(), CHARSET));} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}public static void main(String[] args) {// TODO Auto-generated method stubComUtil comUtil = new ComUtil();comUtil.broadMsg("loves");comUtil.sendMsg("this is a single msg1", new InetSocketAddress("127.0.0.1", BROADCAST_PORT+1));comUtil.sendMsg("this is a single msg2", new InetSocketAddress("127.0.0.1", BROADCAST_PORT+1));}}

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

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

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

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

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

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

  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. 微服务追踪系统,你绝对想不到!
  2. 三极管hFE参数随着Ic,Vc的变化情况
  3. 微软职位内部推荐-SW Engineer II for Azure Network
  4. STL札记3-2(hashtable关联容器set、map)
  5. [Swift]LeetCode45. 跳跃游戏 II | Jump Game II
  6. Lucene教程--入门程序详解
  7. 面试项目 java-服务端2 18h58
  8. laravel修改.env不生效原因以及解决办法
  9. 从SQL过渡至MongoDB查询对照表
  10. 【spring boot基础知识】java.lang.ClassNotFoundException: oracle.jdbc.driver.OracleDriver
  11. python 可视化 画直线_用Python画江苏省地图,实现各地级市数据可视化
  12. js文件位置--为甚有些js必须放在尾部
  13. c++ primer note
  14. Android TTS实现简单阅读器(一)
  15. 解决Steam首次安装更新缓慢 过慢 无反应的问题
  16. OpenGL with QtWidgets:材质、光照贴图
  17. 计算机智能化的例子,工程机械智能化技术案例实例.ppt
  18. 苹果Mac中delete键的七种用法!
  19. JAVA中计算五子棋平局的算法_输入五子棋棋盘判断输赢或平局—程序设计(C语言)...
  20. css 层叠样式表详解

热门文章

  1. 创建自签名证书, 对exe文件进行数字签名
  2. Android Stdio 控制STM32开发板
  3. 卫士处刑者冠军css3边,流放之路决斗者冠军双持刀刃乱舞BD分享
  4. 仟龙教您如何用html做一个酷炫掉渣的点名器
  5. 计算机关闭应用窗口的方法,关闭应用程序窗口的快捷键是
  6. 从零开始了解thinkphp框架,tp框架基础教程
  7. 博客备份工具BlogDown 软件使用感想
  8. [C语言]行列式计算器
  9. 深度学习 - 40. N-Gram 采样与 Session 数据获取 For EGES
  10. 《失业的程序员》(十三):平衡(转载)