java nio web,JavaWeb之三——网络IO和NIO

TCP状态转换图

24ebe37ac13b

24ebe37ac13b

影响网络传输的因素

将一份数据从一个地方正确地传输到另一个地方所需要的时间我们称之为响应时间。

影响这个时间的因素有很多:

24ebe37ac13b

Socket

Java Socket的工作机制

Socket这个概念没有对应到一个具体的实体,它描述计算机之间相互通信的一种抽象功能。

打个比方,可以把Socket比作两个城市之间的交通工具,有了它,就可以在城市之间来回穿梭了。

交通工具有多种,每种交通工具也有相应的交通规则。

Socket也一样,也有多种。大部分情况下我们用的都是基于TCP/IP的流套接字,它是一种稳定的通信协议。

24ebe37ac13b

24ebe37ac13b

建立通信链路

24ebe37ac13b

24ebe37ac13b

24ebe37ac13b

数据传输

24ebe37ac13b

NIO的工作方式

24ebe37ac13b

24ebe37ac13b

NIO的工作机制

24ebe37ac13b

24ebe37ac13b

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.nio.channels.spi.SelectorProvider;

import java.util.Iterator;

/**

* Created by 18351 on 2018/10/23.

*

* TCP/IP的非阻塞方式

* 服务端

*/

public class Server implements Runnable{

//第一个端口

private Integer port1 = 8099;

//第二个端口

private Integer port2 = 9099;

//第一个服务器通道 服务A

private ServerSocketChannel serversocket1;

//第二个服务器通道 服务B

private ServerSocketChannel serversocket2;

//连接1

private SocketChannel clientchannel1;

//连接2

private SocketChannel clientchannel2;

//选择器,主要用来监控各个通道的事件

private Selector selector;

//缓冲区

private ByteBuffer buf = ByteBuffer.allocate(512);

public Server() {

init();

}

/**

* 这个method的作用 :

* 1:是初始化选择器

* 2:打开两个通道

* 3:给通道上绑定一个socket

* 4:将选择器注册到通道上

*/

public void init() {

try {

//创建选择器

this.selector = SelectorProvider.provider().openSelector();

//打开第一个服务器通道

this.serversocket1 = ServerSocketChannel.open();

//告诉程序现在不是阻塞方式的

this.serversocket1.configureBlocking(false);

//获取现在与该通道关联的套接字

this.serversocket1.socket().bind(new InetSocketAddress("localhost", this.port1));

//将选择器注册到通道上,返回一个选择键

//OP_ACCEPT用于套接字接受操作的操作集位

this.serversocket1.register(this.selector, SelectionKey.OP_ACCEPT);

this.serversocket2=ServerSocketChannel.open();

this.serversocket2.configureBlocking(false);

this.serversocket2.socket().bind(new InetSocketAddress("localhost",this.port2));

this.serversocket2.register(this.selector,SelectionKey.OP_ACCEPT);

} catch (Exception e) {

e.printStackTrace();

}

}

/**

* 客户端连接服务器

* @param key

* @throws IOException

*/

public void accept(SelectionKey key) throws IOException{

ServerSocketChannel server = (ServerSocketChannel) key.channel();

if (server.equals(serversocket1)) {

clientchannel1 = server.accept(); //连接到服务端1

clientchannel1.configureBlocking(false);

//OP_READ用于读取操作的操作集位

clientchannel1.register(this.selector, SelectionKey.OP_READ);

} else {

clientchannel2 = server.accept();连接到服务端2

clientchannel2.configureBlocking(false);

//OP_READ用于读取操作的操作集位

clientchannel2.register(this.selector, SelectionKey.OP_READ);

}

}

/**

* 从通道中读取数据

* 并且判断是给那个服务通道的

* @throws IOException

* */

public void read(SelectionKey key) throws IOException {

this.buf.clear();

//通过选择键来找到之前注册的通道

//但是这里注册的是ServerSocketChannel为什么会返回一个SocketChannel??

SocketChannel channel = (SocketChannel) key.channel();

//从通道里面读取数据到缓冲区并返回读取字节数

int count = channel.read(this.buf);

if (count == -1) {

//取消这个通道的注册

key.channel().close();

key.cancel();

return;

}

//将数据从缓冲区中拿出来

String input = new String(this.buf.array()).trim();

//那么现在判断是连接的那种服务

if (channel.equals(this.clientchannel1)) {

System.out.println("欢迎您使用服务A");

System.out.println("您的输入为:" + input);

} else {

System.out.println("欢迎您使用服务B");

System.out.println("您的输入为:" + input);

}

}

@Override

public void run() {

while (true) {

try {

System.out.println("running ... ");

//选择一组键,其相应的通道已为 I/O 操作准备就绪。

this.selector.select();

//返回此选择器的已选择键集

//public abstract Set selectedKeys()

Iterator selectorKeys = this.selector.selectedKeys().iterator();

while (selectorKeys.hasNext()) {

System.out.println("running2 ... ");

//这里找到当前的选择键

SelectionKey key = (SelectionKey) selectorKeys.next();

//然后将它从返回键队列中删除

selectorKeys.remove();

if (!key.isValid()) { // 选择键无效

continue;

}

if (key.isAcceptable()) {

//如果遇到请求那么就响应

this.accept(key);

} else if (key.isReadable()) {

//读取客户端的数据

this.read(key);

}

}

} catch (Exception e) {

e.printStackTrace();

}

}

}

public static void main(String[] args) {

Server server=new Server();

Thread thread=new Thread(server);

thread.start();

}

}

import java.io.IOException;

import java.net.InetAddress;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.SocketChannel;

/**

* Created by 18351 on 2018/10/23.

* TCP/IP非阻塞方式

* 客户端

*/

public class Client {

//创建缓冲区

private ByteBuffer buffer = ByteBuffer.allocate(512);

//访问服务器

public void query(String host, int port) throws IOException {

InetSocketAddress address = new InetSocketAddress(InetAddress.getByName(host), port);

SocketChannel socket = null;

byte[] bytes = new byte[512];

while (true) {

try {

System.in.read(bytes);

socket = SocketChannel.open();

socket.connect(address);

buffer.clear();

buffer.put(bytes);

buffer.flip(); //转换读写

socket.write(buffer);

buffer.clear();

} catch (Exception e) {

e.printStackTrace();

} finally {

if (socket != null) {

socket.close();

}

}

}

}

public static void main(String[] args) throws IOException {

//new Client().query("localhost", 8099);

new Client().query("localhost", 9099);

}

}

NIO的主要原理与使用

24ebe37ac13b

24ebe37ac13b

Buffer的工作方式

24ebe37ac13b

24ebe37ac13b

24ebe37ac13b

24ebe37ac13b

NIO的文件访问方式

24ebe37ac13b

24ebe37ac13b

24ebe37ac13b

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值