Browse Source

socket,filechannel update

master
louzin 6 months ago
parent
commit
b94c6f30bd
  1. 8
      pom.xml
  2. 146
      src/doc/buffer.md
  3. BIN
      src/doc/img/img.png
  4. 78
      src/main/java/com/louzin/niodemo/bufferdemo/buffer3.java
  5. 39
      src/main/java/com/louzin/niodemo/bufferdemo/buffertest.java
  6. 4
      src/main/java/com/louzin/niodemo/bufferdemo/test.java
  7. 28
      src/main/java/com/louzin/niodemo/demo.java
  8. 30
      src/main/java/com/louzin/niodemo/nioFileChannelTest.java
  9. 14
      src/main/java/com/louzin/niodemo/scatterandgather/package-info.java
  10. 39
      src/main/java/com/louzin/niodemo/socketnioclienttest/datagramChannel.java
  11. 89
      src/main/java/com/louzin/niodemo/socketnioclienttest/datagramChannel2.java
  12. 28
      src/main/java/com/louzin/niodemo/socketnioclienttest/socketClientDemo.java
  13. 41
      src/main/java/com/louzin/niodemo/socketniotest/ServerSocketChannelDemo.java
  14. 3
      src/main/resources/bufferreader.txt
  15. 3
      src/main/resources/copy.txt

8
pom.xml

@ -6,4 +6,12 @@
<version>1.0-SNAPSHOT</version>
<name>Archetype - nioDemo</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

146
src/doc/buffer.md

@ -0,0 +1,146 @@
# Buffer
其中Position和Limit的含义取决于Buffer在read还是write模式
无论何种模式,Capacity含义不变
Buffer支持的类型
- ByteBuffer
- MappedByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
![img.png](img/img.png)
## Capacity
内存块,Buffer的固定值
只能写入Byte,Long,Char等类型,若Buffer满了需要清除才能继续写数据
## Position
写的时候代表写入数据当前位置,初始位置指向0,最大值为Capacity-1
读的时候代表读入数据当前位置,初始位置指向0
## Limit
写数据时,Limit表示对Buffer最大写入多少容量,写模式下等于Capacity
读数据时表示还有多少数据可读
## 分配与写数据
### 创建
```java
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
ByteBuffer buffer = ByteBuffer.allocate(48);
CharBuffer charBuffer=ByteBuffer.allocate(1024)
```
### 写数据
#### Channel
```java
int bytesRead = inChannel.read(buf);
//read into buffer
```
#### put()
```java
buf.put(127);
```
### flip()
切换读写模式
### 读数据
#### Buffer
```java
int bytesWrite = inChannel.write(buf);
```
#### get()
```java
byte aByte = buf.get();
```
## 常用方法
### rewind()
position置零,重读buffer数据,limit不变
### clear() compact()
clear直接清除
compact未读数据可继续读
### mark() reset()
使用mark方法标记buffer中的一个特定position,通过reset()恢复这个position
## 缓冲区操作
### 缓冲区分片 slice()
在现有buffer缓冲区中切分出一块新区域
```java
public void bufferSlice(){
ByteBuffer allocate = ByteBuffer.allocate(10);
for(int i=0;i<allocate.capacity();i++){
allocate.put((byte)i);
}
//slice
allocate.position(3);
allocate.limit(7);
ByteBuffer slice = allocate.slice();
for(int i=0;i<slice.capacity();i++){
slice.put((byte) i);
}
// allocate.position(0);//置零
// allocate.limit(allocate.capacity());//指向末尾
while (allocate.hasRemaining()){
System.out.print(allocate.get());
}
System.out.println();
slice.flip();
while (slice.hasRemaining()){
System.out.print(slice.get());
}
}
```
### 只读缓冲区 asReadOnlyBuffer()
asReadOnlyBuffer()将任何常规缓冲区变为只读,这个方法会返回一个与原缓冲区完全相同的缓冲区,并与原缓冲区共享数据,不过只可读
```java
public void readOnlyBuffer(){
ByteBuffer allocate = ByteBuffer.allocate(10);
for(int i=0;i<allocate.capacity();i++){
allocate.put((byte)i);
}
ByteBuffer readOnly=allocate.asReadOnlyBuffer();
readOnly.flip();
while (readOnly.hasRemaining()){
System.out.print(readOnly.get());
}
}
```
若原缓冲区发生变动,只读分区随之变动
### 直接缓冲区 allocateDirect()
加速I/O速度,在使用本方法创建后底层每一次I/O操作之前或之后会尝试避免将缓冲区的内容拷贝到一个中间缓冲区中,或者从一个中间缓冲区中拷贝数据
```java
public void directBuffer() throws IOException {
RandomAccessFile randomAccessFile = new RandomAccessFile("src/main/resources/bufferreader.txt","rw");
RandomAccessFile copy = new RandomAccessFile("src/main/resources/copy.txt","rw");
ByteBuffer byteBuffer =ByteBuffer.allocateDirect(1024);
FileChannel channel = randomAccessFile.getChannel();
FileChannel channel1 = copy.getChannel();
while (true){
byteBuffer.clear();
if(channel.read(byteBuffer)==-1){
break;
}
byteBuffer.flip();
channel1.write(byteBuffer);
}
}
```
### 内存映射文件I/O
```java
static private final int start=0;
static private final int size=1024;
public void memBuffer() throws Exception {
RandomAccessFile randomAccessFile = new RandomAccessFile("src/main/resources/bufferreader.txt","rw");
FileChannel fc = randomAccessFile.getChannel();
MappedByteBuffer mappedByteBuffer= fc.map(FileChannel.MapMode.READ_WRITE,start,size);
mappedByteBuffer.put(0,(byte) 97);
mappedByteBuffer.put(1023,(byte) 122);
randomAccessFile.close();
}
```

BIN
src/doc/img/img.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

78
src/main/java/com/louzin/niodemo/bufferdemo/buffer3.java

@ -0,0 +1,78 @@
package com.louzin.niodemo.bufferdemo;
import org.junit.jupiter.api.Test;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class buffer3 {
@Test
public void bufferSlice(){
ByteBuffer allocate = ByteBuffer.allocate(10);
for(int i=0;i<allocate.capacity();i++){
allocate.put((byte)i);
}
//slice
allocate.position(3);
allocate.limit(7);
ByteBuffer slice = allocate.slice();
for(int i=0;i<slice.capacity();i++){
slice.put((byte) i);
}
// allocate.position(0);//置零
// allocate.limit(allocate.capacity());//指向末尾
while (allocate.hasRemaining()){
System.out.print(allocate.get());
}
System.out.println();
slice.flip();
while (slice.hasRemaining()){
System.out.print(slice.get());
}
}
@Test
public void readOnlyBuffer(){
ByteBuffer allocate = ByteBuffer.allocate(10);
for(int i=0;i<allocate.capacity();i++){
allocate.put((byte)i);
}
ByteBuffer readOnly=allocate.asReadOnlyBuffer();
readOnly.flip();
while (readOnly.hasRemaining()){
System.out.print(readOnly.get());
}
}
@Test
public void directBuffer() throws IOException {
RandomAccessFile randomAccessFile = new RandomAccessFile("src/main/resources/bufferreader.txt","rw");
RandomAccessFile copy = new RandomAccessFile("src/main/resources/copy.txt","rw");
ByteBuffer byteBuffer =ByteBuffer.allocateDirect(1024);
FileChannel channel = randomAccessFile.getChannel();
FileChannel channel1 = copy.getChannel();
while (true){
byteBuffer.clear();
if(channel.read(byteBuffer)==-1){
break;
}
byteBuffer.flip();
channel1.write(byteBuffer);
}
}
static private final int start=0;
static private final int size=1024;
public void memBuffer() throws Exception {
RandomAccessFile randomAccessFile = new RandomAccessFile("src/main/resources/bufferreader.txt","rw");
FileChannel fc = randomAccessFile.getChannel();
MappedByteBuffer mappedByteBuffer= fc.map(FileChannel.MapMode.READ_WRITE,start,size);
mappedByteBuffer.put(0,(byte) 97);
mappedByteBuffer.put(1023,(byte) 122);
randomAccessFile.close();
}
}

39
src/main/java/com/louzin/niodemo/bufferdemo/buffertest.java

@ -0,0 +1,39 @@
package com.louzin.niodemo.bufferdemo;
import org.junit.jupiter.api.Test;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.channels.FileChannel;
public class buffertest {
@Test
public void buffer01() throws IOException {
RandomAccessFile randomAccessFile = new RandomAccessFile("src/main/resources/bufferreader.txt", "rw");
FileChannel channel = randomAccessFile.getChannel();
ByteBuffer allocate = ByteBuffer.allocate(1024);
int read = channel.read(allocate);
allocate.flip();
while (allocate.hasRemaining()){
System.out.print((char) allocate.get());
}
randomAccessFile.close();
}
//intbuffer
@Test
public void buffertest1(){
IntBuffer allocate = IntBuffer.allocate(8);
//write data into buffer
for(int i=0;i<8;i++){
allocate.put(i);
}
allocate.flip();
while (allocate.hasRemaining()){
System.out.print(allocate.get());
}
}
}

4
src/main/java/com/louzin/niodemo/bufferdemo/test.java

@ -1,4 +0,0 @@
package com.louzin.niodemo.bufferdemo;
public class test {
}

28
src/main/java/com/louzin/niodemo/demo.java

@ -0,0 +1,28 @@
package com.louzin.niodemo;
import static java.lang.Thread.sleep;
public class demo{
public static void main(String[] args) throws InterruptedException {
Runnable rb=new Data();
Thread td =new Thread(rb);
td.start();
while(true){
sleep(1000);
System.out.print(3);
}
}
}
class Data implements Runnable {
@Override
public void run() {
while(true) {
try {
sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.print("2");
}
}
}

30
src/main/java/com/louzin/niodemo/nioFileChannelTest.java

@ -0,0 +1,30 @@
package com.louzin.niodemo;
import org.junit.jupiter.api.Test;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
public class nioFileChannelTest {
@Test
public void testRead() throws IOException {
RandomAccessFile randomAccessFile = new RandomAccessFile("src/main/resources/mytest.txt","rw");
FileChannel fileChannel = randomAccessFile.getChannel();
//buffer
ByteBuffer allocate = ByteBuffer.allocate(1024);
fileChannel.read(allocate);
System.out.println(allocate.position());
allocate.put("aac".getBytes(StandardCharsets.UTF_8));
System.out.println(allocate.position());
allocate.flip();
while (allocate.hasRemaining())
System.out.print((char) allocate.get());
fileChannel.close();
allocate.clear();
randomAccessFile.close();
}
}

14
src/main/java/com/louzin/niodemo/scatterandgather/package-info.java

@ -0,0 +1,14 @@
package com.louzin.niodemo.scatterandgather;
//scatter 分散:将数据分散到多个buffer中
//ByteBuffer header = ByteBuffer.allocate(128);
//ByteBuffer body=ByteBuffer.allocate(1024);
//ByteBuffer[] byteBuffers={header,body};
//channel.read(byteBuffers);
//
//scatter Reads只适合固定消息,不适合动态消息
//gahter 聚集:将多个buffer的数据发送到同一个channel
//ByteBuffer header = ByteBuffer.allocate(128);
//ByteBuffer body=ByteBuffer.allocate(1024);
//ByteBuffer[] byteBuffers={header,body};
//channel.write(byteBuffers);

39
src/main/java/com/louzin/niodemo/socketnioclienttest/datagramChannel.java

@ -0,0 +1,39 @@
package com.louzin.niodemo.socketnioclienttest;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.charset.StandardCharsets;
//无连接,面向udp,可任意发送和接受数据包
//UDP不存在真正意义上的连接
//以下的连接是向特定服务器read和write接受和发包
public class datagramChannel {
@Test
public void datagramChannelTest() throws IOException {
DatagramChannel open = DatagramChannel.open();
open.bind(new InetSocketAddress("www.baidu.com",10086));
//receive udp data package
ByteBuffer allocate = ByteBuffer.allocate(64);
allocate.clear();
SocketAddress receive = open.receive(allocate);
//发送数据包
//打开同DatagramChannel open
//配置发送内容
ByteBuffer wrap = ByteBuffer
.wrap("client send".getBytes(StandardCharsets.UTF_8));
//发送数据包
open.send(wrap,new InetSocketAddress("",80));
//read和write只有在connect后才能使用,不然NotYetConnectException
//read未接受到包时PortUnreachableException
open.connect(new InetSocketAddress("",10086));
int readSize = open.read(allocate);
open.write(wrap);
}
}

89
src/main/java/com/louzin/niodemo/socketnioclienttest/datagramChannel2.java

@ -0,0 +1,89 @@
package com.louzin.niodemo.socketnioclienttest;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.ByteChannel;
import java.nio.channels.DatagramChannel;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
public class datagramChannel2 {
//send
@Test
public void sendDataPackage() throws IOException, InterruptedException {
//get Channel
DatagramChannel open = DatagramChannel.open();
InetSocketAddress l = new InetSocketAddress("localhost", 9999);
open.configureBlocking(false);
//send
while (true){
open.send(ByteBuffer.wrap("UDPUDPUDP".getBytes(StandardCharsets.UTF_8)),l);
System.out.println("发送完成");
Thread.sleep(1000);
}
}
@Test
public void receiveDataPackage() throws IOException {
DatagramChannel open = DatagramChannel.open();
open.bind(new InetSocketAddress("localhost",9999));
//通过buffer读取
ByteBuffer allocate = ByteBuffer.allocate(1024);
while (true){
allocate.clear();
SocketAddress receive = open.receive(allocate);
allocate.flip();
System.out.println(receive.toString());
//发送时含有中文,编码处理
System.out.println(Charset.forName("UTF-8").decode(allocate));
}
}
@Test()
public void readWriteTest() throws IOException {
DatagramChannel open = DatagramChannel.open();
open.bind(new InetSocketAddress(9999));
open.connect(new InetSocketAddress("localhost",9999));
open.write(ByteBuffer.wrap("发送12332111111!!!".getBytes(StandardCharsets.UTF_8)));
ByteBuffer allocate = ByteBuffer.allocate(64);
while (true){
allocate.clear();
open.read(allocate);
allocate.flip();
System.out.println(Charset.forName("UTF-8").decode(allocate));
}
}
@Test
public void writeTest() throws IOException, InterruptedException {
DatagramChannel open = DatagramChannel.open();
open.bind(new InetSocketAddress("localhost",9990));
open.connect(new InetSocketAddress("localhost",9990));
while (true){
open.write(ByteBuffer.wrap("发送!!!".getBytes(StandardCharsets.UTF_8)));
System.out.println("发送成功");
Thread.sleep(1000);
}
}
@Test
public void readTest() throws IOException, InterruptedException {
DatagramChannel open = DatagramChannel.open();
open.connect(new InetSocketAddress("localhost",9990));
ByteBuffer allocate = ByteBuffer.allocate(64);
while (true){
Thread.sleep(500);
System.out.println("等待写入");
allocate.clear();
open.read(allocate);
allocate.flip();
System.out.println(Charset.forName("UTF-8").decode(allocate));
}
}
}

28
src/main/java/com/louzin/niodemo/socketnioclienttest/socketClientDemo.java

@ -0,0 +1,28 @@
package com.louzin.niodemo.socketnioclienttest;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
public class socketClientDemo {
@Test
public void createChannel() throws IOException {
//创建SocketChannel
SocketChannel open = SocketChannel
.open(new InetSocketAddress(
"www.baidu.com", 80));
//第二种方法
// SocketChannel open1 = SocketChannel.open();
// open1.connect(new InetSocketAddress(
// "www.baidu.com", 80));
//设置阻塞/非阻塞模式
open.configureBlocking(false);
ByteBuffer allocate = ByteBuffer.allocate(16);
open.read(allocate);
open.close();
System.out.println("ReadOver");
}
}

41
src/main/java/com/louzin/niodemo/socketniotest/ServerSocketChannelDemo.java

@ -0,0 +1,41 @@
package com.louzin.niodemo.socketniotest;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
public class ServerSocketChannelDemo {
@Test
public void createPort() throws IOException, InterruptedException {
int port = 8888;
ByteBuffer wrap = ByteBuffer.wrap("hello socket".getBytes(StandardCharsets.UTF_8));
//ServerSocketChannel
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//ServerSocketChannel未实现绑定,所以需要手动绑定
//得到socket对象,完成对其绑定
serverSocketChannel.socket().bind(new InetSocketAddress(port));
//非阻塞模式运行
serverSocketChannel.configureBlocking(false);
//监听是否有新连接传入
while (true){
//返回值若为null,则无传入
//若为阻塞模式,则会卡到这里直到连接建立
SocketChannel accept = serverSocketChannel.accept();
System.out.println("等待连接!");
if(accept==null){
System.out.println("未发现新连接!");
Thread.sleep(2000);
}else {
System.out.println("发现新连接!!"+accept.socket().getRemoteSocketAddress());
wrap.rewind();//指针0
accept.write(wrap);
accept.close();
}
}
}
}

3
src/main/resources/bufferreader.txt

@ -0,0 +1,3 @@
abc
def
hij

3
src/main/resources/copy.txt

@ -0,0 +1,3 @@
abc
def
hij
Loading…
Cancel
Save