一,nio中的网络io(nio的非阻塞式网络通信)
1,使用nio完成网络通信的3要素
-通道(Channel): 负责链接
SelectableChannel
SocketChannel
ServerSocketChannel
DatagramChannel
Pipe.SinkChannel Pipe.SourceChannel
-缓冲区(Buffer):负责数据存取
-选择器(Selector): 负责监控SelectableChannel状态
SelectableChannel对象的多路复用器 。
package com.momo.demo;
import org.junit.Test;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class Demo1 {
@Test
public void server() throws IOException {
//获取通道
ServerSocketChannel sschannel = ServerSocketChannel.open();
//绑定端口
sschannel.bind(new InetSocketAddress(12345));
FileChannel outchannel = FileChannel.open(Paths.get("222.jpg"),StandardOpenOption.WRITE,StandardOpenOption.CREATE); //获取客户端链接 SocketChannel schannel = sschannel.accept(); //创建缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); //接收数据,保存 while (schannel.read(buf)!=-1){ buf.flip(); outchannel.write(buf); buf.clear(); } } @Test //客户端 public void client() throws IOException { //获取通道 SocketChannel schannel = SocketChannel.open(new InetSocketAddress(InetAddress.getLocalHost(), 12345)); FileChannel inchannel = FileChannel.open(Paths.get("111.jpg"), StandardOpenOption.READ); //创建缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); //读取本地文件,发送到服务端 while (inchannel.read(buf)!=-1){ buf.flip(); schannel.write(buf); buf.clear(); } //释放资源 inchannel.close(); schannel.close(); }
}
package com.momo.demo;
import org.junit.Test;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
//客户端发送数据,服务端反馈数据
public class Demo2 {
@Test
public void server() throws IOException {
//获取通道
ServerSocketChannel sschannel = ServerSocketChannel.open();
//绑定端口
sschannel.bind(new InetSocketAddress(12345));
FileChannel outchannel = FileChannel.open(Paths.get("222.jpg"),StandardOpenOption.WRITE,StandardOpenOption.CREATE); //获取客户端链接 SocketChannel schannel = sschannel.accept(); //创建缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); //接收数据,保存 while (schannel.read(buf)!=-1){ buf.flip(); outchannel.write(buf); buf.clear(); } //给客户端反馈信息 buf.put("我收到了".getBytes()); buf.flip(); schannel.write(buf); schannel.close(); outchannel.close(); sschannel.close(); } @Test //客户端 public void client() throws IOException { //获取通道 SocketChannel schannel = SocketChannel.open(new InetSocketAddress(InetAddress.getLocalHost(), 12345)); FileChannel inchannel = FileChannel.open(Paths.get("111.jpg"), StandardOpenOption.READ); //创建缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); //读取本地文件,发送到服务端 while (inchannel.read(buf)!=-1){ buf.flip(); schannel.write(buf); buf.clear(); } schannel.shutdownOutput(); //接收服务端额反馈信息 int len = 0; while ((len=schannel.read(buf))!=-1){ buf.flip(); System.out.println(new String(buf.array(),0,len)); buf.clear(); } //释放资源 inchannel.close(); schannel.close(); }
}
2,选择器
-如何获取选择器?
Selector.open() 方法获取
-如何把通道注册到选择器上?
使用通道的register(Selector s,int key) 方法
当调用这个方法的时候,要把通道注册到选择器上,需要指定
需要监测的事件,通过第二个参数来传递。
事件的类型,java给我们封装到了SelectionKey 中,用几个常量表示的。
如果需要监听多个事件,可以使用| 隔开
-你要让监听器监听什么事件?
java都已经给我们封装好了,在SelectionKey中。
-SelectionKey:表示SelectableChannel 和 Selector 之间的关系。
每次给选择器中注册通道的时候要选择一个事件(选择键)
static int OP_ACCEPT
就绪事件
static int OP_CONNECT
链接事件
static int OP_READ
可读
static int OP_WRITE
可写
int interestOps()
获取感兴趣的事件集合
int readyOps()
获取通道中已经准备就绪的状态集合
SelectableChannel channel()
获取注册通道
boolean isAcceptable()
测试此密钥的通道是否已准备好接受新的套接字连接。
boolean isConnectable()
测试此密钥的通道是否已完成或未完成其套接字连接操作。
boolean isReadable()
测试此密钥的频道是否可以阅读。
boolean isWritable()
测试此密钥的通道是否准备好进行写入。
package com.momo.demo;
import org.junit.Test;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
//非阻塞式
public class Demo3 {
@Test
public void server() throws IOException {
//获取通道
ServerSocketChannel ssChannel = ServerSocketChannel.open();
//切换非阻塞模式
ssChannel.configureBlocking(false);
//绑定端口
ssChannel.bind(new InetSocketAddress(12345));
//获取选择器
Selector selector = Selector.open();
//使用选择器监听状态,把通道注册到监听器中,指定需要监听的状态(事件)
ssChannel.register(selector, SelectionKey.OP_ACCEPT);
//循环获取选择器上已经准备就绪的事件
while (selector.select()>0){
//获取当前在选择器中已经准备就绪的事件
//Set keys = selector.selectedKeys();
Iterator it = selector.selectedKeys().iterator();
// for (SelectionKey key : keys) {
while (it.hasNext()){
SelectionKey key = it.next();
//判断是否有准备就绪的事件
if(key.isAcceptable()){
//如果准备就绪,获取客户端链接
SocketChannel sChannel = ssChannel.accept();
//切换非阻塞模式
sChannel.configureBlocking(false);
//把通道注册到选择器上
sChannel.register(selector,SelectionKey.OP_READ);
}else if(key.isReadable()){
//获取可读通道
SocketChannel sChannel = (SocketChannel)key.channel();
//读取数据
ByteBuffer buf = ByteBuffer.allocate(1024);
int len = 0;
while ((len=sChannel.read(buf))!=-1){
buf.flip();
System.out.println(new String(buf.array(),0,len));
buf.clear();
}
}
//移除选择键(取消处理过的事件)
it.remove();
}
}
}
@Test //客户端 public void client() throws IOException { //获取通道 SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 12345)); //调用方法切换到非阻塞模式 sChannel.configureBlocking(false); //创建缓冲区 ByteBuffer buf = ByteBuffer.allocate(1024); //发送数据 buf.put((new Date()+":你好").getBytes()); buf.flip(); sChannel.write(buf); buf.clear(); //释放资源 sChannel.close(); }
}
3,常用的类和方法 -SocketChannel static SocketChannel open(SocketAddress remote) 打开套接字通道并将其连接到远程地址。 SocketChannel shutdownInput() 关闭连接进行阅读,不关闭频道。 SocketChannel shutdownOutput() 关闭连接以进行写入,而不关闭通道。 SelectionKey register(Selector sel, int ops) SelectableChannel configureBlocking(boolean block) -ServerSocketChannel ServerSocketChannel open() ServerSocketChannel bind(SocketAddress local) SocketChannel accept() SelectableChannel configureBlocking(boolean block) SelectionKey register(Selector sel, int ops) -Selector static Selector open() 打开选择器。 int select() 选择一组其相应通道准备好进行I / O操作的键。 Set selectedKeys() 返回此选择器的选择键集。
package com.momo.demo;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
public class Client {
public static void main(String[] args) throws IOException {
SocketChannel sChannel = SocketChannel.open(new InetSocketAddress(InetAddress.getLocalHost(), 6666));
sChannel.configureBlocking(false);
ByteBuffer buf = ByteBuffer.allocate(1024); Scanner sc = new Scanner(System.in); System.out.println("请输入:"); while (sc.hasNext()){ String str = sc.next(); buf.put((new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date())+":"+str).getBytes()); buf.flip(); sChannel.write(buf); buf.clear(); } sChannel.close(); }
}
package com.momo.demo;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
public class Server {
public static void main(String[] args) throws IOException {
ServerSocketChannel ssChannel = ServerSocketChannel.open();
ssChannel.configureBlocking(false);
ssChannel.bind(new InetSocketAddress(6666));
Selector selector = Selector.open(); ssChannel.register(selector, SelectionKey.OP_ACCEPT); while (selector.select()>0){ Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()){ SelectionKey sk = it.next(); if(sk.isAcceptable()){ SocketChannel sChannel = ssChannel.accept(); sChannel.configureBlocking(false); sChannel.register(selector,SelectionKey.OP_READ); }else if(sk.isReadable()){ SocketChannel sChannel = (SocketChannel)sk.channel(); ByteBuffer buf = ByteBuffer.allocate(1024); int len = 0; while ((len=sChannel.read(buf))>0){ buf.flip(); System.out.println(new String(buf.array(),0,len)); buf.clear(); } } it.remove(); } } }
}
二,DatagramChannel
1,java nio包中DatagramChannel 是一个能收发upd包的通道
2,步骤
-打开DatagramChannel
-接收或者发送数据
package com.momo.demo;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.util.Scanner;
public class Send {
public static void main(String[] args) throws IOException {
DatagramChannel dc = DatagramChannel.open();
dc.configureBlocking(false);
ByteBuffer buf = ByteBuffer.allocate(1024);
Scanner sc = new Scanner(System.in);
while (sc.hasNext()){
String str = sc.next();
buf.put(str.getBytes());
buf.flip();
dc.send(buf,new InetSocketAddress("127.0.0.1",8888));
buf.clear();
}
dc.close();
}
}
package com.momo.demo;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
public class Receive {
public static void main(String[] args) throws IOException {
DatagramChannel dc = DatagramChannel.open();
dc.configureBlocking(false);
dc.bind(new InetSocketAddress(8888));
Selector selector = Selector.open(); dc.register(selector, SelectionKey.OP_READ); while (selector.select()>0){ Iterator<SelectionKey> it = selector.selectedKeys().iterator(); while (it.hasNext()){ SelectionKey sk = it.next(); if(sk.isReadable()){ ByteBuffer buf = ByteBuffer.allocate(1024); dc.receive(buf); buf.flip(); System.out.println(new String(buf.array(),0,buf.limit())); buf.clear(); } it.remove(); } } }
}
三,管道(Pipe)
1,java nio 管道 是2个线程之间的单向数据链接
-Pipe 有一个source 通道 和一个sink 通道。
数据写到sink通道,从source读取
package com.momo.demo;
import org.junit.Test;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.Pipe;
public class Demo6 {
@Test
public void test1() throws IOException {
//获取管道
Pipe pipe = Pipe.open();
//写数据
Pipe.SinkChannel sink = pipe.sink();
ByteBuffer buf = ByteBuffer.allocate(1024); buf.put("你好。小日子过的不错的人。".getBytes()); buf.flip(); sink.write(buf); //读取数据 Pipe.SourceChannel source = pipe.source(); buf.flip(); int len = source.read(buf); System.out.println(new String(buf.array(),0,len)); source.close(); sink.close(); }
}
四,juint单元测试
1,测试?
2,分类:
-黑盒测试:不需要写代码,给输入值,看程序是否能够输出期望的值。
-白盒测试:需要写代码的。关注程序具体的执行流程。
3,juint单元测试好处
-可以书写一系列的测试方法,对项目所有的接口或者方法进行单元测试。
-启动后,自动化测试,并判断执行结果, 不需要人为的干预。
-只需要查看最后结果,就知道整个项目的方法接口是否通畅。
-每个单元测试用例相对独立,由Junit 启动,自动调用。不需要添加额外的调用语句。
-添加,删除,屏蔽测试方法,不影响其他的测试方法。 开源框架都对JUnit 有相应的支持。
4,使用
-有一个MyMath类,里面有很多方法要进行测试
sum()
-步骤:
导入juint的jar包
编写一个测试类,测试类放在测试包 com.momo.test TestMyMath
定义测试方法 加入@Test注解 可以独立运行
testSum()
返回值void
参数空
判断结果:一般使用断言,红色表示失败,绿色表示成功。
package com.momo.util;
public class MyMath {
public int sum(int a,int b){
return a+b;
}
}
package com.momo.test;
import com.momo.util.MyMath;
import org.junit.Assert;
import org.junit.Test;
public class TestMyMath {
@Test
public void testSum(){
MyMath mm = new MyMath();
int sum = mm.sum(2, 3);
// System.out.println(sum);
//断言 我认为结果应该是什么
Assert.assertEquals(5,sum);
//Assert.assertEquals(4,sum);
}
/* @Test
public void testAvg(){
}*/
}
5,需要知道的注解
-@Test 测试方法上加
-@Before 在所有测试方法执行前,会自动执行
-@After 在所有测试方法执行完成后,会自动执行
package com.momo.test;
import com.momo.util.MyMath;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class TestMyMath {
//在执行测试方法之前需要完成的一些初始化操作
//在所有测试方法执行前,会自动执行
@Before
public void init(){
System.out.println("创建依赖对象,完成一些初始化操作");
}
@Test
public void testSum(){
// System.out.println("创建依赖对象,完成一些初始化操作");
System.out.println("测试代码。。。");
MyMath mm = new MyMath();
int sum = mm.sum(2, 3);
// System.out.println(sum);
//断言 我认为结果应该是什么
Assert.assertEquals(5,sum);
//Assert.assertEquals(4,sum);
// System.out.println("释放依赖对象");
}
//在所有测试方法执行完成后,会自动执行
@After
public void close(){
System.out.println("释放依赖对象");
}
/* @Test public void testAvg(){ System.out.println("创建依赖对象,完成一些初始化操作"); 。。。。 System.out.println("释放依赖对象"); }*/ }
标签:java,nio,SocketChannel,管道,ByteBuffer,import,buf,junit From: https://blog.51cto.com/u_16230968/7513807