Java NIO(五)套接字通道
Socket通道
Socket通道和文件通道有着不一样的特征:
- Socket通道类可以运行于非阻塞模式,并且是可选的。这两个特征可以激活大程序(如网络服务和中间件组件)巨大的可伸缩性和灵活性,因此再也没有为每个Socket连接添加一个线程的必要。这一特性避免了管理大量线程所需的上下文交换总开销,借助NIO,一个或几个线程就可以管理成百上千个Socket连接,并且没有或只有很少的性能损失
- 全部的Socket通道类(SocketChannel,ServerSocketChannel,DatagramChannel)在被实例化时都会创建一个对应的Socket对象,如Socket,ServerSocket,DatagramSocket,这些Socket可以通过调用对应通道类的socket()方法来获取。此外,这三个Socket都有getChannel()方法
- 每个Socket通道都有一个关联的java.net.socket对象,反之却不是这样。如果使用传统方式(直接实例化)创建了一个Socket对象,它不会关联有Socket通道,且它的getChannel()方法总是返回null
打开SocketChannel
SocketChannel channel = SocketChannel.open();
channel.connect(new InetSocketAddress("http://xxx,com", 80));
关闭SocketChannel
channel.close();
从SocketChannel读数据
ByteBuffer buf = ByteBuffer.allocate(100);
int bytr = channel.read(buf);
该方法将数据从SocketChannel读到Buffer中,read()方法的返回值表示读了多少字节到Buffer中,当返回值为-1时,表示已经读到了流的末尾
写入SocketChannel
String str = "some thing";
ByteBuffer buf = ByteBuffer.allocate(100);
buf.put(str.getBytes());
buf.flip();
while(buf.hasRemaining){
socketChannel.write(buf);
}
socketChannel.close();
注意: SocketChannel.write()方法的调用是在一个while循环中的。Write()方法无法保证能写多少字节到SocketChannel。所以,我们重复调用write()直到Buffer没有要写的字节为止。
非阻塞模式
要把一个Socket通道置于非阻塞模式,要依赖父类的父类SelectableChannel:
public abstract class SelectableChannel extends AbstractInterruptibleChannel implements Channel {
...
public abstract void configureBlocking(boolean block) throws IOException;
public abstract boolean isBlocking();
public abstract Object blockngLock();
...
}
从SelectableChannel的API可以看出,设置或重新设置一个通道的阻塞模式是很简单的,只要调用configureBlocking()方法即可,传递参数值为true则设为阻塞模式。参数值为false,则为非阻塞模式。同时,通过调用isBlocking()方法来判断是否为被阻塞。blockingLock()方法会返回一个不透明的对象引用,返回的对象是通道实现修改阻塞模式时内部使用的,只有拥有此对象的锁的线程才能更改通道的阻塞模式,对于确保在执行代码的关键部分时Socket通道的阻塞模式不会改变以及在不影响其他线程的前提下暂时改变阻塞模式来说,这个方法是非常方便的。
connect()方法
非阻塞模式下调用connect()方法,该方法可能在连接建立完之前就返回,为了确定连接是否建立,调用finishConnect()方法
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("http://xxx.com", ));
while(!socketChannel.finishConnect()){
//some codes 如果没有连接成功则...
}
write()方法
非阻塞模式下,write()方法在尚未写出任何内容时可能就返回了。所以需要在循环中调用write()
read()方法
非阻塞模式下,read()方法在尚未读取到任何数据时可能就返回了。所以需要关注它的int返回值,它会告诉你读取了多少字节
补充: 非阻塞模式与选择器搭配会工作的更好,通过将一或多个SocketChannel注册到Selector,可以询问选择器哪个通道已经准备好了读取,写入等
ServerSocketChannel
Java NIO中的 ServerSocketChannel 是一个可以监听新进来的TCP连接的通道, 就像标准IO中的ServerSocket一样。ServerSocketChannel类在 java.nio.channels包中
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.socket().bind(new InetSocketAddress(9999));
while(true){
SocketChannel socketChannel = serverChannel.accept();
}
打开ServerSocketChannel
ServerSocketChannel serverChannel = ServerSocketChannel.open();
关闭ServerSocketChannel
serverChannel.close();
监听新进来的连接
通过ServerSocketchannel.accept()方法监听新进来的连接。accept()方法返回一个包含新进来的连接的SocketChannel,因此,accept()方法会一直阻塞到有新连接到达
通常不会仅仅只监听一个连接,在while循环中调用 accept()方法
while(true){
SocketChannel socketChannel = serverSocketChannel.accept();
}
非阻塞模式
ServerSocketChannel可以设置成非阻塞模式。在非阻塞模式下,accept() 方法会立刻返回,如果还没有新进来的连接,返回的将是null。 因此,需要检查返回的SocketChannel是否是null
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.socket().bind(new InetSocketAddress(9999));
while(true){
SocketChannel socketChannel = serverChannel.accept();
if(socketChannel != null){
//some codes
}
}
Socket通道的服务端程序
public class SocketServer
{
public static void main(String[] args) throws Exception
{
int port = 1234;
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false); //非阻塞模式
ServerSocket ss = ssc.socket();
ss.bind(new InetSocketAddress(port));
while (true)
{
SocketChannel sc = ssc.accept();
if (sc == null)
{
// 如果当前没有数据,等待1秒钟再次轮询是否有数据,在学习了Selector之后此处可以使用Selector
Thread.sleep(1000);
}
else {
ByteBuffer bb = ByteBuffer.allocate(100);
sc.read(bb);
bb.flip();
while (bb.hasRemaining()){
System.out.print((char)bb.get());
}
sc.close();
System.exit(0);
}
}
}
}
Socket通道的客戶端程序
public class NonBlockingSocketClient
{
private static final String STR = "Hello World!";
private static final String REMOTE_IP= "127.0.0.1"; public static void main(String[] args) throws Exception {
int port = 1234;
SocketChannel sc = SocketChannel.open();
sc.configureBlocking(false); //非阻塞模式
sc.connect(new InetSocketAddress(REMOTE_IP, port));
while (!sc.finishConnect()){
System.out.println("同" + REMOTE_IP+ "的连接正在建立,请稍等!");
Thread.sleep(10);
}
System.out.println("连接已建立,待写入内容至指定ip+端口!时间为" + System.currentTimeMillis());
ByteBuffer bb = ByteBuffer.allocate(STR.length());
bb.put(STR.getBytes());
bb.flip(); // 写缓冲区的数据之前一定要先反转(flip)
sc.write(bb);
bb.clear();
sc.close();
}
}
DatagramChannel
Java NIO中的DatagramChannel是一个能收发UDP包的通道。因为UDP是无连接的网络协议,所以不能像其它通道那样读取和写入。它发送和接收的是数据包
打开DatagramChannel
DatagramChannel datagramChannel = DatagramChannel.open();
datagramChannel.socket().bind(new InetSocketAddress(8089));
receive()方法
ByteBuffer buf = ByteBuffer.allocate(100);
datagramChannel.receive(buf);
receive()方法会将接收到的数据包内容复制到指定的Buffer. 如果Buffer容不下收到的数据,多出的数据将被丢弃
send()方法
String str = "some codes";
ByteBuffer buf = ByteBuffer.allocate(100);
buf.put(str.getBytes());
buf.flip();
int byt = datagramChannel.send(buf, new InetSocketAddress("xxx.com", 80));
这个例子发送一串字符到”xxx.com”服务器的UDP端口80。 因为服务端并没有监控这个端口,所以什么也不会发生。也不会通知你发出的数据包是否已收到,因为UDP在数据传送方面没有任何保证
连接到特点地址
datagramChannel.connect("xxx.com", 80);
可以将DatagramChannel“连接”到网络中的特定地址的。由于UDP是无连接的,连接到特定地址并不会像TCP通道那样创建一个真正的连接。而是锁住DatagramChannel ,让其只能从特定地址收发数据
当连接后,也可以使用read()和write()方法,就像在用传统的通道一样。只是在数据传送方面没有任何保证
int bytesRead = datagramChannel.read(buf);
int bytesWritten = datagramChannel.write(but);
Java NIO(五)套接字通道的更多相关文章
- Java NIO之套接字通道
1.简介 前面一篇文章讲了文件通道,本文继续来说说另一种类型的通道 -- 套接字通道.在展开说明之前,咱们先来聊聊套接字的由来.套接字即 socket,最早由伯克利大学的研究人员开发,所以经常被称为B ...
- java输入输出 -- Java NIO之套接字通道
一.简介 前面一篇文章讲了文件通道,本文继续来说说另一种类型的通道 – 套接字通道.在展开说明之前,咱们先来聊聊套接字的由来.套接字即 socket,最早由伯克利大学的研究人员开发,所以经常被称为Be ...
- Java NIO SocketChannel套接字通道
原文链接:http://tutorials.jenkov.com/java-nio/socketchannel.html 在Java NIO体系中,SocketChannel是用于TCP网络连接的套接 ...
- Java NIO(四)文件通道
文件通道 通道是访问I/O服务的导管,I/O可以分为广义的两大类:File I/O和Stream I/O.那么相应的,通道也有两种类型,它们是文件(File)通道和套接字(Socket)通道.文件通道 ...
- Java网络编程--套接字Socket
一.套接字Socket IP地址标志Internet上的计算机,端口号标志正在计算机上运行的进程(程序). 端口号被规定为一个16位的0--65535之间的整数,其中,0--1023被预先定义的服务通 ...
- Java如何使套接字向单个客户端显示消息?
在Java编程中,如何使用套接字向单个客户端显示消息? 以下示例演示了如何使用Socket类的ssock.accept()方法向单个套接字客户端上显示消息. package com.yiibai; i ...
- Java链接db2套接字出错
### Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could ...
- 网络协议学习笔记(五)套接字Socket
概述 前面学习网络知识的时候写过一篇关于套接字的随笔见<JAVA SOCKET 详解>,现在本人正在系统的学习网络知识,现在除了温故知新之外,在详细的学习记录一下套接字的知识. Socke ...
- Java NIO Channel to Channel Transfers通道传输接口
原文链接:http://tutorials.jenkov.com/java-nio/channel-to-channel-transfers.html 在Java NIO中如果一个channel是Fi ...
随机推荐
- MeayunDB学习笔记(一) MeayunDB介绍及安装
系列目录 MeayunDB介绍-高性能分布式内存数据库 MeayunDB学习笔记(一)MeayunDB介绍及安装 MeayunDB学习笔记(二)批量导入数据 MeayunDB学习笔记(三)索引应用 ...
- Java学习笔记2——数据类型和转换
前提知识: 1字节=8bit:1bit以一个二极管表示,代表2个状态(0或者1):2bit代表22即4种状态(00,01,10,11),8bit即是28即256种状态,16bit即是65536种状态. ...
- PhotoZoom控制面板简介说明
PhotoZoom是一款极其简单的图片无损放大工具,简单几步渲染出完美的放大照片,呈现无与伦比的画质效果.即可虽然简单,菜单和面板的功能很少,但却是设计师的必备神器,因为其简单易用性,它的软件菜单命令 ...
- 洛谷P1120 小木棍 [数据加强版]搜索
玄学剪支,正好复习一下搜索 感觉搜索题的套路就是先把整体框架打出来,然后再一步一步优化剪枝 1.从maxv到sumv/2枚举长度(想一想,为什么) 2. 开一个桶,从大到小开始枚举 3. 在搜索中,枚 ...
- node——buffer
buffe方便数据的传输,可一次性传输一部分数据一.类型介绍1.javascript语言没有读取或操作二进制数据的机制.2.Node.js中引入了Buffer类型可以使我们操作TCP流或文件流3.Bu ...
- Linux的mysql搭建
1.centos7默认安装mariadb数据库 #yum remove mariadb* 2.wget mysql数据库地址 如果是普通用户,请提权 sudo提权 3.yum local ins ...
- javascript 富文本 注意事项
富文本编辑器 div内嵌iframe iframe body contenteditable属性 true 整个iframe 即为可编辑框,创建时注意事项: 1.编辑 焦点问题 弹出新控件时为控件设置 ...
- nyoj48-小明的调查作业
48-小明的调查作业 内存限制:64MB时间限制:1000msSpecial Judge: No accepted:3submit:4 题目描述: 小明的老师布置了一份调查作业,小明想在学校中请一些同 ...
- jquery 去重
var yearArray = new Array(2009, 2009, 2010, 2010, 2009, 2010); $.unique(yearArray); alert(yearArray) ...
- 【ACM-ICPC 2018 南京赛区网络预赛 L】Magical Girl Haze
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 定义dis[i][j]表示到达i这个点. 用掉了j次去除边的机会的最短路. dis[1][0]= 0; 在写松弛条件的时候. 如果用 ...