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 ...
随机推荐
- matplotlib显示中文字体
原始地址:http://zanyongli.i.sohu.com/blog/view/195716528.htm matplotlib 1.0.0版 对于3.0的可能不太适用,要注意语法结构! C:/ ...
- spring boot的项目结构问题
问题:spring boot项目能够正常启动,但是在浏览器访问的时候会遇到404的错误,Whitelable Error Page 404 分析及解决方案:首先Application文件要放在项目的外 ...
- 使用meta实现页面的定时刷新或跳转
<meta http-equiv="refresh" content="5"> 这个表示当前页面每5秒钟刷一下,刷一下~ <meta http ...
- promise待看文档备份
http://swift.gg/2017/03/27/promises-in-swift/ http://www.cnblogs.com/feng9exe/p/9043715.html https:/ ...
- .NET 请求和接收FormData的值
<body> <div> <!-- 上传单个文件---> <form action="/Home/UpdateFile2" enctype ...
- MongoDB_可视化工具Robo 3T
Robo 3T可以对MongoDB进行可视化操作. Robo 3T安装 官网下载地址:https://robomongo.org/ 进入官网,点击下载,Studio 3T功能更全面,基础功能是免费的, ...
- VS Code中编写html(5) 标签的布局设置
1 <!--首先在div中添加四个span标签--> <div> <!--span*4+tab--> <!--span{span$}*4--> < ...
- Javaee 方法的格式和注意事项
1.构造方法的格式是什么?有哪些注意事项? 修饰符+方法名称+(参数列表),构造的方法没有返回值,方法名称要和类名一样,有属性参数的需要在成员变量前加this,参数列表的值要和指定的方法格式相同. ...
- 路飞学城Python-Day75
1.什么是Django? Django是一个web框架,也是python中最火的一个框架,应用最多,内容最全 2.什么是web框架? python的一个脚本就是一个应用程序,web框架就是和前端有关系 ...
- 路飞学城Python-Day52
27-选项卡 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...