Socket(2)
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();
}
}
运行:
- 打开服务端
- 打开客户端
- 在客户端窗口键盘输入后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();
} }
运行:
- 打开多个此窗口
- 在窗口键盘输入后enter
Socket(2)的更多相关文章
- socket读写返回值的处理
在调用socket读写函数read(),write()时,都会有返回值.如果没有正确处理返回值,就可能引入一些问题 总结了以下几点 1当read()或者write()函数返回值大于0时,表示实际从缓冲 ...
- Socket聊天程序——Common
写在前面: 上一篇记录了Socket聊天程序的客户端设计,为了记录的完整性,这里还是将Socket聊天的最后一个模块--Common模块记录一下.Common的设计如下: 功能说明: Common模块 ...
- Socket聊天程序——客户端
写在前面: 上周末抽点时间把自己写的一个简单Socket聊天程序的初始设计和服务端细化设计记录了一下,周二终于等来毕业前考的软考证书,然后接下来就是在加班的日子度过了,今天正好周五,打算把客户端的详细 ...
- Socket聊天程序——服务端
写在前面: 昨天在博客记录自己抽空写的一个Socket聊天程序的初始设计,那是这个程序的整体设计,为了完整性,今天把服务端的设计细化记录一下,首页贴出Socket聊天程序的服务端大体设计图,如下图: ...
- Socket聊天程序——初始设计
写在前面: 可能是临近期末了,各种课程设计接踵而来,最近在csdn上看到2个一样问答(问题A,问题B),那就是编写一个基于socket的聊天程序,正好最近刚用socket做了一些事,出于兴趣,自己抽了 ...
- Java中的Socket的用法
Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...
- Android Socket连接PC出错问题及解决
最近测试问题:Android 通过Socket链接电脑,ip和端口都是正确的,也在同一网段,可android端就是报异常如下: 解决办法:测试电脑的防火墙可能开着,在控制面板把防火墙打开即可.
- Linux下的C Socket编程 -- server端的继续研究
Linux下的C Socket编程(四) 延长server的生命周期 在前面的一个个例子中,server在处理完一个连接后便会立即结束掉自己,然而这种server并不科学啊,server应该是能够一直 ...
- Mono 3.2.3 Socket功能迎来一稳定的版本
由于兴趣自己业余时间一直在搞.net下面的通讯应用,mono的存在得以让.NET程序轻松运行在Linux之下.不过经过多尝试Socket相关功能在Mono下的表现并不理想.不管性能还是吞吐能力方面离我 ...
- Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!
随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...
随机推荐
- iOS打电话、发短信
方式一:使用该方法进行拨号之后,当电话挂断之后不会反回应用程序,会停留在电话记录界面,不会反回应用程序 NSURL *url = [NSURL URLWithString:@"te ...
- yii中第三方库
yii中存在一些路径别名:ext:表示包含了所有第三方扩展的目录 参考:http://www.yiiframework.com/doc/guide/1.1/zh_cn/basics.namespac ...
- Centos linux php扩展安装步骤
使用phpinfo()函数输出PHP信息,然后找到Configuration File (php.ini) apachectl 其设计意图是帮助管理员控制Apache httpd后台守护进程的功能. ...
- SQL数据库基本语句
SQL特点--> 1)综合统一.SQL是集数据定义.数据操作和数据控制于一体,语言峰峰统一,可独立完成数据库生命周期的所有活动. 2)高度非过程化.SQL语言是高度非过程化语言,当进行数据操作时 ...
- Windbg 内存命令 《第四篇》
内存是存储数据.代码的地方,通过内存查看命令可以分析很多问题.相关命令可以分为:内存查看命令和内存统计命令.内存统计命令用来分析内存的使用状况. 一.查看内存 有非常丰富的内存查看命令,它们被容易为d ...
- 【MySQL】数据导出导入成CSV格式
一.自动输出中文字符集 select * from db into outfile 'test.csv' CHARACTER SET gbk fields terminated by ',' opti ...
- 织梦dedecms简略标题调用标签用法指南
我们在使用织梦DEDECMS建站过程中,为了使调用的文章标题简短且相对完整(原文标题太长),只好使用了调用简略标题这个方法,使标题显示为简短标题,指向标题时显示完整的标题.并获得文章静态地址链接 下面 ...
- Splash Screen开场屏在Android中的实现
很多网友可能发现近期Tencent推出的手机QQ Android版包含了一个开场屏Splash Screen载入效果,通常游戏或大型软件打开时可能需要一个释放解析资源的过程,需要一个前台的动画播放和后 ...
- shell脚本中切换用户并执行命令
1.切换用户并执行命令 su 用户名 -c "命令" 2.切换用户并执行脚本 su 用户名 -s /bin/bash 脚本路径 3.切换用户并执行命令集su 用户名 << ...
- CentOS 5.x版本升级Mysql
#-----------------------------CentOS 5.x版本升级Mysql ------------------#! /bin/sh #1.关闭selinuxcp -rp /e ...