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 ...
随机推荐
- PCL:PCL与MFC 冲突总结
(1):max,min问题 MFC程序过程中使用STL一些类编译出错,放到Console Application里一切正常.比如: void CMyDialog::OnBnClickedButton1 ...
- ZBrush细说3D海盗角色的创建艺术
一提到海盗,就不由自主想到了<加勒比海盗>,那个帅得一塌糊涂的杰克船长更是让人夜不能寐寝难安,但在艺术的世界里,角色无美丑,今天我们要讲的这位海盗,就与“帅气”八竿子打不着了,它甚至有点古 ...
- Brain Network (hard) CodeForces - 690C 简单倍增 + 一些有趣的推导
Code: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; ...
- 将JavaBean对象/List或Set或Map对象转成JSON方式
一.通过Struts2插件包(即使用Struts框架)自动生成JSON文本 二.使用第三方工具,将JavaBean对象/List或Set或Map对象转成JSON 准备导入第三方jar包: >c ...
- nyoj286-动物统计
动物统计 时间限制:1000 ms | 内存限制:65535 KB 难度:2 描述 在美丽大兴安岭原始森林中存在数量繁多的物种,在勘察员带来的各种动物资料中有未统计数量的原始动物的名单.科学家想判 ...
- MAVN(自动创建maven项目骨架) 项目架构的生成
1.Maven的项目架构生成 A.打开DOS命令窗口选定文件的更跟目录 B:输入命令 mvn archetype:generate C:根据提示输入对应的标识 如图: 最后提示 SUCCESS 即为 ...
- 转[总结]FFMPEG视音频编解码零基础学习方法 .
http://blog.csdn.net/leixiaohua1020/article/details/15811977 在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视 ...
- ubuntu的LAMP环境搭建
服务器的搭建,经典组合:LAMP(Linux+Apache+Mysql+PHP) unbuntu源更新:sudo apt update 更新:sudo apt upgrade 安装Apache:sud ...
- ❝ Windows系统的FTP上传下载脚本 ❞
运行环境:windows 脚本功能:从目标系统下载数据库备份文件*.dmp 执行方法:windows任务计划定时调用文件ftp.bat 文件1:ftp.bat echo 开始备份日期: >> ...
- hdu 1556 线段树区间延迟更新好题
656mS #include<stdio.h> #include<stdlib.h> #define N 110000 struct node { int x,y,yanchi ...