UDP:

UDP协议没有socket之间的虚拟链路,也就是说没有“握手”阶段,只是发送接收。

可以想象成直播,直播时如果中间网络不好,不会事后重新播放之前的,而是直接跳过。

也就是说一方只负责发送,一方只负责接收,发送方不关心对方会不会接到数据。

TCP协议:可靠,传输大小无限制,但是需要建立连接后传输数据。

UDP协议:不可靠,传输大小限制在64K以下,但是不需要建立连接。

相关类:

DatagramSocket:接收和发送的数据报。

receive(DatagramPacket P)://从DatagramSocket接收数据。
send(DatagramPacket P)://从DatagramSocket发送数据。

DatagramSocket并不知道数据发送到哪里去,而是由DatagramPacket来指定。

DatagramPacket:用来承载数据的,代表数据报。

DatagramPacket(byte buf[],int length, InetAnddress addr,int port);//一个装有传送数据的数组,加一个接收方的地址以及端口。
DatagramPacket(byte buf[],int length);//只有装有数据的数组,意味着接收数据报。
/*那么反馈数据应该怎么办,DatagramSocket也不知道从哪发过来的数据。
DatagramPacket提供了3个方法:*/
InetAddress getAddress();//当接收到一个数据的时候返回发送主机IP地址。发送时反之。
Int getPort();//当接收到一个数据的时候返回发送主机端口。发送时反之。
SocketAddress getSocketAddress();//当接收到一个数据的时候返回打包成发送主机IP&PORT的SocketAddress。发送时反之。

实例:

服务端代码:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket; public class UDPServer {
public static final int PORT = 30000;
// 定义每个数据报的最大大小为4KB
private static final int DATA_LEN = 4096;
// 定义接收网络数据的字节数组
byte[] inBuff = new byte[DATA_LEN];
// 以指定字节数组创建准备接收数据的DatagramPacket对象
private DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length);
// 定义一个用于发送的DatagramPacket对象
private DatagramPacket outPacket;
// 定义一个字符串数组,服务器端发送该数组的元素
String[] books = new String[] { "疯狂Java讲义", "轻量级Java EE企业应用实战",
"疯狂Android讲义", "疯狂Ajax讲义" }; public void init() throws IOException {
try (
// 创建DatagramSocket对象
DatagramSocket socket = new DatagramSocket(PORT)) {
// 采用循环接收数据
for (int i = 0; i < 1000; i++) {
// 读取Socket中的数据,读到的数据放入inPacket封装的数组里
socket.receive(inPacket);
// 判断inPacket.getData()和inBuff是否是同一个数组
System.out.println(inBuff == inPacket.getData());
// 将接收到的内容转换成字符串后输出
System.out.println(new String(inBuff, 0, inPacket.getLength()));
// 从字符串数组中取出一个元素作为发送数据
byte[] sendData = books[i % 4].getBytes();
// 以指定的字节数组作为发送数据,以刚接收到的DatagramPacket的
// 源SocketAddress作为目标SocketAddress创建DatagramPacket
outPacket = new DatagramPacket(sendData, sendData.length,
inPacket.getSocketAddress());
// 发送数据
socket.send(outPacket);
}
}
} public static void main(String[] args) throws IOException {
new UDPServer().init();
}
}

客户端代码:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner; public class UDPClient
{
// 定义发送数据报的目的地
public static final int DEST_PORT = 30000;
public static final String DEST_IP = "127.0.0.1";
// 定义每个数据报的最大大小为4KB
private static final int DATA_LEN = 4096;
// 定义接收网络数据的字节数组
byte[] inBuff = new byte[DATA_LEN];
// 以指定的字节数组创建准备接收数据的DatagramPacket对象
private DatagramPacket inPacket =
new DatagramPacket(inBuff , inBuff.length);
// 定义一个用于发送的DatagramPacket对象
private DatagramPacket outPacket = null;
public void init()throws IOException
{
try(
// 创建一个客户端DatagramSocket,使用随机端口
DatagramSocket socket = new DatagramSocket())
{
// 初始化发送用的DatagramSocket,它包含一个长度为0的字节数组
outPacket = new DatagramPacket(new byte[0] , 0
, InetAddress.getByName(DEST_IP) , DEST_PORT);
// 创建键盘输入流
Scanner scan = new Scanner(System.in);
// 不断地读取键盘输入
while(scan.hasNextLine())
{
// 将键盘输入的一行字符串转换成字节数组
byte[] buff = scan.nextLine().getBytes();
// 设置发送用的DatagramPacket中的字节数据
outPacket.setData(buff);
// 发送数据报
socket.send(outPacket);
// 读取Socket中的数据,读到的数据放在inPacket所封装的字节数组中
socket.receive(inPacket);
System.out.println(new String(inBuff , 0
, inPacket.getLength()));
}
}
}
public static void main(String[] args)
throws IOException
{
new UDPClient().init();
}
}

运行:

  1. 打开服务端
  2. 打开客户端
  3. 在客户端窗口键盘输入后enter

MulticastSocket:

当使用UDP协议时,如果想让一个客户端发送的聊天信息被转发到其他所有的客户端则比较困难,可以考虑在服务器端使用Set集合来保存所有的客户端信息,

每当接收到一个客户端的数据报之后,程序检查该数据报的源SocketAddress是否在Set集合中,如果不在就将该SocketAddress添加到该Set集合中。

这样又涉及一个问题:可能有些客户端发送一个数据报之后永久性地退出了程序,但服务器端还将该客户端的SocketAddress保存在Set集合中……

总之,这种方式需要处理的问题比较多,编程比较烦琐。幸好Java为UDP协议提供了MulticastSocket类,通过该类可以轻松地实现多点广播。

MulticastSocket没有客户端服务端之说,都是发往广播地址中,只要join到广播地址中,那么所有MulticastSocket都会接到此数据。

MulticastSocket类是DatagramSocket的子类
JoinGroup(InetAddress mulicastAddr):将该MulticastSocket加入到广播地址中。发送广播那么我们需要用到广播地址(230.0.0.1)。
LeaveGroup(InetAddress mulicastAddr): 与JoinGroup(InetAddress mulicastAddr)相反。
SetTimeToLive(int ttl):设置数据可跨多少个网络。
 *设置ttl为1我们就在局域网内使用。

ttl我们可以在CMD命令窗口中通过ping命令可以确认到TTL对应值。

当ttl=0时,指定数据报应停留在本地主机。

当ttl=1时,指定数据报发送到局域网。

当ttl=32时,指定数据报发送到本站点的网络上。

当ttl=64时,指定数据报发送到本地区。

当ttl=128时,指定数据报发送到本大洲内。

当ttl=255时,指定数据报发送所有地方。

实例:

在原来的DatagramSocket的客户端代码中进行了修改。

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Scanner; public class MulticastSocketDemo implements Runnable {
// 定义发送数据报的目的地
public static final int DEST_PORT = 30000;
public static final String MULTICAST_IP = "230.0.0.1";
public InetAddress multicastAddr = null;
// 定义每个数据报的最大大小为4KB
private static final int DATA_LEN = 4096;
// 定义接收网络数据的字节数组
byte[] inBuff = new byte[DATA_LEN];
// 以指定的字节数组创建准备接收数据的DatagramPacket对象
private DatagramPacket inPacket = new DatagramPacket(inBuff, inBuff.length);
// 定义一个用于发送的DatagramPacket对象
private DatagramPacket outPacket = null;
// 定义一个MulticastSocket对象
private MulticastSocket socket = null; public void init() throws IOException {
try {
// 创建一个MulticastSocket,必須指定端口,指定端口为DEST_PORT,
socket = new MulticastSocket(DEST_PORT);
//创建一个广播地址
multicastAddr = InetAddress.getByName(MULTICAST_IP);
// 将MulticastSocket加入到广播地址中
socket.joinGroup(multicastAddr);
// 使用在局域网中
socket.setTimeToLive(1);
// 发送的数据报回送到自身
socket.setLoopbackMode(false);
// 初始化发送用的MulticastSocket,它包含一个长度为0的字节数组
outPacket = new DatagramPacket(new byte[0], 0,multicastAddr, DEST_PORT);
// 创建接收数据的线程
new Thread(this).start();
// 创建键盘输入流
Scanner scan = new Scanner(System.in);
// 不断地读取键盘输入,没有数据时会堵塞,等待输入
while (scan.hasNextLine()) {
// 将键盘输入的一行字符串转换成字节数组
byte[] buff = scan.nextLine().getBytes();
// 设置发送用的DatagramPacket中的字节数据
outPacket.setData(buff);
// 发送数据报
socket.send(outPacket);
}
} finally {
socket.close();
}
} @Override
public void run() {
// TODO Auto-generated method stub
try {
// 读取Socket中的数据,读到的数据放在inPacket所封装的字节数组中
while (true) {
socket.receive(inPacket);
System.out.println(new String(inBuff, 0, inPacket.getLength()));
}
} catch (IOException e) {
// TODO Auto-generated catch block
if(socket !=null){
try {
socket.leaveGroup(multicastAddr);
socket.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
e.printStackTrace();
}
} public static void main(String[] args) throws IOException {
new MulticastSocketDemo().init();
} }

运行:

  1. 打开多个此窗口
  2. 在窗口键盘输入后enter

Socket(2)的更多相关文章

  1. socket读写返回值的处理

    在调用socket读写函数read(),write()时,都会有返回值.如果没有正确处理返回值,就可能引入一些问题 总结了以下几点 1当read()或者write()函数返回值大于0时,表示实际从缓冲 ...

  2. Socket聊天程序——Common

    写在前面: 上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块--Common模块记录一下.Common的设计如下: 功能说明: Common模块 ...

  3. Socket聊天程序——客户端

    写在前面: 上周末抽点时间把自己写的一个简单Socket聊天程序的初始设计和服务端细化设计记录了一下,周二终于等来毕业前考的软考证书,然后接下来就是在加班的日子度过了,今天正好周五,打算把客户端的详细 ...

  4. Socket聊天程序——服务端

    写在前面: 昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图: ...

  5. Socket聊天程序——初始设计

    写在前面: 可能是临近期末了,各种课程设计接踵而来,最近在csdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了 ...

  6. Java中的Socket的用法

                                   Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...

  7. Android Socket连接PC出错问题及解决

    最近测试问题:Android 通过Socket链接电脑,ip和端口都是正确的,也在同一网段,可android端就是报异常如下: 解决办法:测试电脑的防火墙可能开着,在控制面板把防火墙打开即可.

  8. Linux下的C Socket编程 -- server端的继续研究

    Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...

  9. Mono 3.2.3 Socket功能迎来一稳定的版本

    由于兴趣自己业余时间一直在搞.net下面的通讯应用,mono的存在得以让.NET程序轻松运行在Linux之下.不过经过多尝试Socket相关功能在Mono下的表现并不理想.不管性能还是吞吐能力方面离我 ...

  10. Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!

    随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...

随机推荐

  1. FastDFS的安装配置

    一:实验描述: fastdfs 介绍 FastDFS是一个开源的分布式文件系统,它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题.特别 ...

  2. Windows Azure - App Services

    1. 需要了解的概念:App Service Plan, Resource Group 2. Create an ASP.NET web app in Azure App Services 3. Cr ...

  3. GLSL 中的光照计算

    理论知识转载地址:http://blog.csdn.net/ym19860303/article/details/25545933 1.Lambert模型(漫反射) 环境光: Iambdiff = K ...

  4. MFC读取XML文件并解析

    现在经常会对XML文件进行操作,怎么在MFC下去读和解析XML文件呢?直接上代码: 首先得等在stdafx.h中加入这句,以引入MSXML命名空间 #import <msxml3.dll> ...

  5. MFC六大核心机制之二:运行时类型识别(RTTI)

    上一节讲的是MFC六大核心机制之一:MFC程序的初始化,本节继续讲解MFC六大核心机制之二:运行时类型识别(RTTI). typeid运算子 运行时类型识别(RTTI)即是程序执行过程中知道某个对象属 ...

  6. cordova local notification plugin

    cordova plugin add org.apache.cordova.device cordova plugin add https://github.com/katzer/cordova-pl ...

  7. ENVI 5.0 Beta 体验——影像数据的显示

    ENVI 5.0 Beta采用了全新的软件界面,数据的显示和操作跟以往的三视窗方式有很大的区别,下面一块体验一下. 对于栅格数据的显示方面,5.0有了非常大的改进,采用的全新的金字塔计算方法,在第一次 ...

  8. asp.net中导出Execl的方法

    一.asp.net中导出Execl的方法: 在 asp.net中导出Execl有两种方法,一种是将导出的文件存放在服务器某个文件夹下面,然后将文件地址 输出在浏览器上:一种是将文件直接将文件输出流写给 ...

  9. php中使用end方法报错

    <b>Strict Standards</b>:  Only variables should be passed by reference in <b> 1.如果 ...

  10. 第五章_PHP流程控制

    1.顺序结构 2.分支结构 2.1 if...else <?php $today=date("w"); //获取今天星期几 if($today==0){ echo 'Sund ...