java nio 教程例子_java nio文件传输例子

使用nio传输文件需要注意的是会出现粘包和服务器端缓冲区满的情况。第一种情况,客户端发送30次数据,而服务器端只接收到18次的情况,这种情况出现

主要是服务器端是以流的方式接收数据,它并不知道每次客户端传输数据的大小而造成的。第二种情况是服务器端缓冲区满,导致客户端数据传输失败,这种情况

下,需要判断传输int send =

client.write(sendBuffer)的send值,如果send值为0,则服务器端的数据缓冲区可能满了。

客户端实现代码:import java.io.FileInputStream;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.FileChannel;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.SocketChannel;

import java.util.Set;

public class FileClient {

private int port = 8000;

/* 发送数据缓冲区 */

private static ByteBuffer sendBuffer = ByteBuffer.allocate(1024);

/* 接受数据缓冲区 */

private static ByteBuffer revBuffer = ByteBuffer.allocate(1024);

private InetSocketAddress SERVER;

private static Selector selector;

private static SocketChannel client;

public FileClient(){

try{

SERVER = new InetSocketAddress("localhost", port);

init();

}

catch(Exception e){

e.printStackTrace();

}

}

private void init(){

try {

SocketChannel socketChannel = SocketChannel.open();

socketChannel.configureBlocking(false);

selector = Selector.open();

socketChannel.register(selector, SelectionKey.OP_CONNECT);

socketChannel.connect(SERVER);

while (true) {

selector.select();

SetkeySet = selector.selectedKeys();

for (final SelectionKey key : keySet) {

if(key.isConnectable()){

client = (SocketChannel)key.channel();

client.finishConnect();

client.register(selector, SelectionKey.OP_WRITE);

}

else if(key.isWritable()){

sendFile(client);

}

}

keySet.clear();

}

} catch (Exception e) {

e.printStackTrace();

}

}

private void sendFile(SocketChannel client) {

FileInputStream fis = null;

FileChannel channel = null;

try {

// fis = new FileInputStream("E:\\1.txt");

// fis = new FileInputStream("E:\\1.rar");

fis = new FileInputStream("G:\\3.rar");

channel = fis.getChannel();

int i = 1;

int count = 0;

while((count = channel.read(sendBuffer)) != -1) {

sendBuffer.flip();

int send = client.write(sendBuffer);

System.out.println("i===========" + (i++) + " count:" + count + " send:" + send);

// 服务器端可能因为缓存区满,而导致数据传输失败,需要重新发送

while(send == 0){

Thread.sleep(10);

send = client.write(sendBuffer);

System.out.println("i重新传输====" + i + " count:" + count + " send:" + send);

}

sendBuffer.clear();

}

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

channel.close();

fis.close();

client.close();

} catch (Exception e) {

e.printStackTrace();

}

}

}

public static void main(String[] args){

new FileClient();

}

}

服务器端import java.io.FileOutputStream;

import java.net.InetSocketAddress;

import java.net.ServerSocket;

import java.nio.ByteBuffer;

import java.nio.channels.FileChannel;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.ServerSocketChannel;

import java.nio.channels.SocketChannel;

import java.util.Set;

public class FileServer {

private int port = 8000;

/* 发送数据缓冲区 */

private static ByteBuffer revBuffer = ByteBuffer.allocate(1024);

private static Selector selector;

private static FileOutputStream fout;

private static FileChannel ch;

public FileServer(){

try{

init();

}

catch(Exception e){

e.printStackTrace();

}

}

private void init() throws Exception{

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.configureBlocking(false);

ServerSocket serverSocket = serverSocketChannel.socket();

serverSocket.bind(new InetSocketAddress(port));

selector = Selector.open();

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

System.out.println("server start on port:" + port);

while (true) {

try {

selector.select();// 返回值为本次触发的事件数

SetselectionKeys = selector.selectedKeys();

for (SelectionKey key : selectionKeys) {

ServerSocketChannel server = null;

SocketChannel client = null;

int count = 0;

if (key.isAcceptable()) {

server = (ServerSocketChannel) key.channel();

System.out.println("有客户端连接进入=============)");

client = server.accept();

client.configureBlocking(false);

client.register(selector, SelectionKey.OP_READ);

fout = new FileOutputStream("G:\\" + client.hashCode() + ".rar");

ch = fout.getChannel();

} else if (key.isReadable()) {

client = (SocketChannel) key.channel();

revBuffer.clear();

count = client.read(revBuffer);

int k = 0;

// 循环读取缓存区的数据,

while(count > 0){

System.out.println("k=" + (k++) + " 读取到数据量:" + count);

revBuffer.flip();

ch.write(revBuffer);

fout.flush();

revBuffer.clear();

count = client.read(revBuffer);

}

if(count == -1){

client.close();

ch.close();

fout.close();

}

}

else if (key.isWritable()) {

System.out.println("selectionKey.isWritable()");

}

}

System.out.println("=======selectionKeys.clear()");

selectionKeys.clear();

} catch (Exception e) {

e.printStackTrace();

break;

}

}

}

public static void main(String[] args){

new FileServer();

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值