Java I/O之NIO Socket
PS:本文简单介绍下旧I/O和NIO下的Socket通讯,仅以UDP来示例。
TCP/IP协议
首先简单回顾下TCP/IP协议 
Application:应用程序;Socket:套接字;Host:主机;Channel:通信信道;Ethernet:以太网;Router:路由器;Network Layer:网络层;Transport Layer:传输层。
在TCP/IP协议族中,底层由基础的通信信道构成,如以太网或调制解调器拨号连接。这些信道由网络层(network layer)使用,而网络层则完成将分组报文传输到它们的目的地址的工作(也就是路由器的功能)。TCP/IP协议族中属于网络层的唯一协议是IP协议,它使两个主机间的一系列通信信道和路由器看起来像是一条单一的主机到主机的信道。
IP协议提供了一种数据报服务:每组分组报文都由网络独立处理和分发,就像信件或包裹通过邮政系统发送一样。为了实现这个功能,每个IP报文必须包含一个保存其目的地址(address)的字段,就像你所投递的每份包裹都写明了收件人地址。(我们随即会对地址进行更详细的说明。)尽管绝大部分递送公司会保证将包裹送达,但IP协议只是一个"尽力而为"(best-effort)的协议:它试图分发每一个分组报文,但在网络传输过程中,偶尔也会发生丢失报文,使报文顺序被打乱,或重复发送报文的情况。
IP协议层之上称为传输层(transport layer)。它提供了两种可选择的协议:TCP协议和UDP协议。这两种协议都建立在IP层所提供的服务基础上,但根据应用程序协议(application protocols)的不同需求,它们使用了不同的方法来实现不同方式的传输。TCP协议和UDP协议有一个共同的功能,即寻址。回顾一下,IP协议只是将分组报文分发到了不同的主机,很明显,还需要更细粒度的寻址将报文发送到主机中指定的应用程序,因为同一主机上可能有多个应用程序在使用网络。TCP协议和UDP协议使用的地址叫做端口号(port numbers),都是用来区分同一主机中的不同应用程序。TCP协议和UDP协议也称为端到端传输协议(end-to-end transport protocols),因为它们将数据从一个应用程序传输到另一个应用程序,而IP协议只是将数据从一个主机传输到另一主机。
TCP协议能够检测和恢复IP层提供的主机到主机的信道中可能发生的报文丢失、重复及其他错误。TCP协议提供了一个可信赖的字节流(reliable byte-stream)信道,这样应用程序就不需要再处理上述的问题。TCP协议是一种面向连接(connection-oriented)的协议:在使用它进行通信之前,两个应用程序之间首先要建立一个TCP连接,这涉及到相互通信的两台电脑的TCP部件间完成的握手消息(handshake messages)的交换。使用TCP协议在很多方面都与文件的输入输出(I/O, Input/Output)相似。实际上,由一个程序写入的文件再由另一个程序读取就是一个TCP连接的适当模型。另一方面,UDP协议并不尝试对IP层产生的错误进行修复,它仅仅简单地扩展了IP协议"尽力而为"的数据报服务,使它能够在应用程序之间工作,而不是在主机之间工作。因此,使用了UDP协议的应用程序必须为处理报文丢失、顺序混乱等问题做好准备。
旧I/O的Socket示例
//服务器端
DatagramSocket servSocket = null;
byte[] buf = new byte[1024];
DatagramPacket datapkg = new DatagramPacket(buf, buf.length);
try {
servSocket = new DatagramSocket(5008);
while (true) {
servSocket.receive(datapkg);
//一般使用多线程来处理....
System.out.println("服务器接收了客户端:" + datapkg.getAddress()
+ " 的数据:" + new String(buf, 0, datapkg.getLength()));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
servSocket.close();
}
//客户端
DatagramSocket clientSocket=new DatagramSocket();
byte[] msg="this is a test message".getBytes();
DatagramPacket datapkg=new DatagramPacket(msg, msg.length, new InetSocketAddress("127.0.0.1", 5008));
clientSocket.send(datapkg);
clientSocket.close();
上面只是简单地示例,实际用应用中需要多线程,特别是服务器端,接收到数据报文后一般需要使用多线程来处理的。
NIO的Socket
旧I/O Socket是阻塞式的,我们通过上例可以看到使用了while(true)在那忙等(很傻吧),当然你可以使用多线程来避开阻塞,但这个解决办法会产生它自己的问题 ― 即线程开销,线程开销同时影响性能和可伸缩性。
新NIO Socket可以使用非阻塞式的(如果你一定要把NIO Socket用作阻塞式的,也不会有人拦你的^_^),实际上是采取Reactor模式,或者说是Observer模式为我们监察I/O端口,如果有内容进来,就会帮我们记录下来,当我们需要的时候再取出来,这样,我们就不必开启多个线程死等,从外界看,实现了流畅的I/O读写,不堵塞了。
而这个非阻塞模式就是由NIO中的类Selector来完成的,它类似一个观察者:只要我们把需要探知的channel事件注册到Selector上,我们接着做别的事情,当channel有事件发生时就会主动通知selector,我们可以轮询selector就知道那些channel可操作,然后我们再从这个Channel中读取数据,放心,包准能够读到,接着我们可以处理这些数据。
NIO中的通道和缓冲器在前面一篇博文中有介绍,我们来看下非阻塞式的代码示例
// 服务器端
DatagramChannel servChannel = DatagramChannel.open();
servChannel.socket().bind(new InetSocketAddress("127.0.0.1", 5008));
// 如果使用selector,此处必须设置为非阻塞式的
servChannel.configureBlocking(false); ByteBuffer buf = ByteBuffer.allocate(1024); Selector selector = Selector.open();
// 注册事件OP_ACCEPT和OP_CONNECT用于TCP,OP_READ和OP_WRITE可用于UDP和TCP
servChannel.register(selector, SelectionKey.OP_READ); // 轮询selector
while (true) {
if (selector.select() > 0) {
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
if (key.isReadable()) {
buf.clear();
SocketAddress clientAdrress = ((DatagramChannel) key
.channel()).receive(buf);
buf.flip();
System.out.println("服务器接收了客户端:" + clientAdrress
+ " 的数据:" + buf.asCharBuffer());
}
it.remove();
}
}
}
虽然说得天花乱坠,但到目前为止我还是没太明白使用这种观察者模式的好处,最后还是避不开忙等。(PS:关于I/O Socket和NIO Socket的对比优势可参考这里。)
推荐一本书:《Java Tcp/Ip Socket编程》
Java I/O之NIO Socket的更多相关文章
- java基础-网络编程(Socket)技术选型入门之NIO技术
java基础-网络编程(Socket)技术选型入门之NIO技术 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.传统的网络编程 1>.编写socket通信的MyServer ...
- Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制
Java网络编程和NIO详解1:JAVA 中原生的 socket 通信机制 JAVA 中原生的 socket 通信机制 摘要:本文属于原创,欢迎转载,转载请保留出处:https://github.co ...
- Java nio socket与as3 socket(粘包解码)连接的应用实例
对Java nio socket与as3 socket连接的简单应用 <ignore_js_op>Java nio socket与as3 socket连接的应用实例.rar (9.61 K ...
- NIO【同步非阻塞io模型】关于 NIO socket 的详细总结【Java客户端+Java服务端 + 业务层】【可以客户端间发消息】
1.前言 以前使用 websocket来实现双向通信,如今深入了解了 NIO 同步非阻塞io模型 , 优势是 处理效率很高,吞吐量巨大,能很快处理大文件,不仅可以 做 文件io操作, 还可以做sock ...
- Java I/O and NIO [reproduced]
Java I/O and NIO.2---Five ways to maximize Java NIO and NIO.2---Build more responsive Java applicati ...
- 深入浅出NIO Socket实现机制
前言 Java NIO 由以下几个核心部分组成: Buffer Channel Selector 以前基于net包进行socket编程时,accept方法会一直阻塞,直到有客户端请求的到来,并返回so ...
- java与C++之间进行SOCKET通讯要点简要解析
原文链接: http://blog.csdn.net/hslinux/article/details/6214594 java与C++之间进行SOCKET通讯要点简要解析 hslinux 0.篇外语 ...
- Java网络编程和NIO详解开篇:Java网络编程基础
Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为 ...
- Java网络编程和NIO详解8:浅析mmap和Direct Buffer
Java网络编程与NIO详解8:浅析mmap和Direct Buffer 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NI ...
随机推荐
- webx--petstore
配置对应环境,运行petstore 通过官网给的命令行方法,来运行petstore petstore是java ee的经典学习案例,下载链接 如何运行呢? 参见官网给的指导:webx官网 git cl ...
- IOS开发缓存机制之—本地缓存机制
功能需求 这个缓存机制满足下面这些功能. 1.可以将数据缓存到本地磁盘. 2.可以判断一个资源是否已经被缓存.如果已经被缓存,在请求相同的资源,先到本地磁盘搜索. 3.可以判断文件缓存什么时候过期.这 ...
- Div里面载入另一个页面的实现(取代框架)(AJax)
随着框架越来越不火了,HTML5就不对框架支持了,iframe也只有url了,Div就担当了此大任 DIV+CSS在页面部局确实也很让人满意,使用也更方便 今天突然遇到一个问题,那就是需要导入另一个页 ...
- Linux文件权限与目录配置
一.linux文件属性 用户组概念:假如主机有两个团体,第一个团体名为projecta,里面有class1,class2,class3:第二个团体名为projecb,里面有class4,class5, ...
- pureMVC简单示例及其原理讲解五(Facade)
本节将讲述Facade,Proxy.Mediator.Command的统一管家.自定义Facade必须继承Facade,在本示例中自定义Facade名称为ApplicationFacade,这个名称也 ...
- SecureCRT 保存FTP用户登录密码
Connect连接对话框->右键选择Session->选择属性->选择Connection 中的 Logon Actions->在右侧进行设置:
- 固定表头带滚动条的HTML表格
http://blog.csdn.net/daryl715/article/details/1883677 <html> <head> </head> <BO ...
- loadrunner controller:实时查看VUser的运行情况
1) 如下图,在Run标签页,点击"Vusers..."打开Vuser窗口: 2) 如下图选中一个Vuser点击按钮可以打开Run-Time Vie ...
- 基于UDP协议的socket通信
服务器端: 1.创建DatagramSocket,指定端口号 2.创建DatagramPacket 3.接收客户端发送的数据信息 4.读取数据 客户端: 1.定义发送信息 2.创建DatagramPa ...
- iOS 图片水印、图片合成文字或图片实现
这个需求可能有时候会碰到,比如自己的照片加版权,打水印等 网上的方法,有不少感觉不全对,或者需求不是特全,这里我总结了3种场景下的需求: 1.本地图片合成文字 2.本地图片合成图片 3.网络图片先下载 ...