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(); 
                Set<SelectionKey> keySet = 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();// 返回值为本次触发的事件数 
                Set<SelectionKey> selectionKeys = 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(); 
    } 
}

原创文章,作者:奋斗,如若转载,请注明出处:https://blog.ytso.com/10585.html

(0)
上一篇 2021年7月19日
下一篇 2021年7月19日

相关推荐

发表回复

登录后才能评论