Skip to content

Instantly share code, notes, and snippets.

@honwhy
Created January 12, 2020 08:13
Show Gist options
  • Save honwhy/d5df556383bc13c15ce5cc75f778abc6 to your computer and use it in GitHub Desktop.
Save honwhy/d5df556383bc13c15ce5cc75f778abc6 to your computer and use it in GitHub Desktop.
用nio写ftpclient(未完)
package org.example;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.function.Function;
import java.util.logging.Logger;
public class MyFTP {
private static Selector selector;
private static ScheduledExecutorService scheduledExecutor;
private String hostname;
//private int port;
protected int _replyCode;
protected ArrayList<String> _replyLines;
protected boolean _newReplyString;
protected String _replyString;
protected String _controlEncoding;
static {
try {
selector = Selector.open();
} catch (IOException e) {
Logger.getLogger(MyFTP.class.getName()).warning("failed to open selector");
}
//TODO set Thread Factory
scheduledExecutor = Executors.newSingleThreadScheduledExecutor();
//scheduledExecutor.schedule();
}
public static void main(String[] args) throws IOException, InterruptedException {
System.out.println("connecting...");
MyFTP myFTP = new MyFTP();
myFTP.connect("localhost", 21);
}
public void connect(String hostname, int port)
throws SocketException, IOException, InterruptedException {
this.hostname = hostname;
//_connect(InetAddress.getByName(hostname), port, null, -1);
SocketChannel ch = SocketChannel.open();
ch.configureBlocking(false);
SelectionKey sk = ch.register(selector, SelectionKey.OP_CONNECT|SelectionKey.OP_READ);
sk.attach((Function<Void, Void>) nil -> {
try {
System.out.println("isConnectable" + sk.isConnectable());
if (sk.isConnectable()) {
SocketChannel socketChannel = (SocketChannel) sk.channel();
//System.out.println("connected");
socketChannel.finishConnect();
doSelect();
} else if (sk.isReadable()) {
System.out.println("isReadable:" + sk.isReadable());
ByteBuffer byteBuffer = ByteBuffer.allocate(256);
try {
SocketChannel ch2 = (SocketChannel) sk.channel();
int bytesWrite = ch.read(byteBuffer);
if (bytesWrite != -1) {
MyFTP.this._replyString = new String(byteBuffer.array(), 0, bytesWrite);
System.out.println(MyFTP.this._replyString);
}
} catch (IOException e) {
e.printStackTrace();
}
}
//socketChannel.finishConnect();
//ByteBuffer loginBuf = ByteBuffer.wrap("USER user".getBytes());
//socketChannel.write(loginBuf);
doSelect();
} catch (IOException e) {
e.printStackTrace();
}
return null;
});
ch.connect(new InetSocketAddress(hostname, port));
doSelect();
Thread.sleep(10*1000L);
}
private void doSelect() throws IOException {
selector.select();
Set<SelectionKey> sks = selector.selectedKeys();
Iterator<SelectionKey> itr = sks.iterator();
if (itr.hasNext()) {
SelectionKey key = itr.next();
Function<Void,?> fun = (Function<Void, ?>) key.attachment();
fun.apply(null);
itr.remove();
}
}
}
@honwhy
Copy link
Author

honwhy commented Jan 12, 2020

很多问题没有搞懂
1.模仿org.apache.commons.net.ftp.FTPClient暴露出来的api应该是阻塞式的,MyFTP应该如何去处理从异步到阻塞呢
2.nio的channel如何确定已经读完了返回了呢,需要阅读ftp协议解析control流和data流吗,end_of_file是一个。
3.如何处理与链接池的关系呢
给MyFTP打上标记,是空闲还是使用中来确定是否新建MyFTP实例,而Selector是所有MyFTP公用的,多路复用与多线程编程是不是有冲突呢
我觉得应该多点从Netty实现中获得参考。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment