Roh*_*ish 29 java sockets ip port-scanning
我制作了非常简单的端口扫描程序,但它运行速度太慢,所以我正在寻找方法使其扫描速度更快.这是我的代码:
public boolean portIsOpen(String ip, int port, int timeout) {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return true;
} catch (Exception ex) {
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
此代码在此测试特定端口是否在特定IP上打开.对于超时,我使用最小值200,因为当我降低时,它没有足够的时间来测试端口.那么它运行良好,但从0到65535扫描需要太多.有没有其他方法可以在不到5分钟的时间内从0扫描到65535?
Bru*_*eis 64
如果65536端口中的每一个都需要200ms(在最坏的情况下,防火墙会阻止所有内容,从而使您在每个端口都达到超时),数学很简单:您需要13k秒,或大约3小时一半.
您有2个(非独占)选项可以加快速度:
由于该操作是I /界O(对比势必CPU -也就是说,你花时间等待I/O,而不是为一些巨大的计算来完成),您可以用很多很多的线程.尝试从20开始.他们将其中的3个半小时分开,因此最大预期时间约为10分钟.请记住,这会对另一方施加压力,即扫描的主机将看到具有"不合理"或"奇怪"模式的巨大网络活动,使扫描非常容易检测.
最简单的方法(即最小的更改)是使用ExecutorService和Future API:
public static Future<Boolean> portIsOpen(final ExecutorService es, final String ip, final int port, final int timeout) {
return es.submit(new Callable<Boolean>() {
@Override public Boolean call() {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return true;
} catch (Exception ex) {
return false;
}
}
});
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以执行以下操作:
public static void main(final String... args) {
final ExecutorService es = Executors.newFixedThreadPool(20);
final String ip = "127.0.0.1";
final int timeout = 200;
final List<Future<Boolean>> futures = new ArrayList<>();
for (int port = 1; port <= 65535; port++) {
futures.add(portIsOpen(es, ip, port, timeout));
}
es.shutdown();
int openPorts = 0;
for (final Future<Boolean> f : futures) {
if (f.get()) {
openPorts++;
}
}
System.out.println("There are " + openPorts + " open ports on host " + ip + " (probed with a timeout of " + timeout + "ms)");
}
Run Code Online (Sandbox Code Playgroud)
如果您需要知道哪些端口是开放的(不只是多少,如上面的例子),你需要改变功能的返回类型Future<SomethingElse>,在这里SomethingElse将举行港口和扫描的结果,东西喜欢:
public final class ScanResult {
private final int port;
private final boolean isOpen;
// constructor
// getters
}
Run Code Online (Sandbox Code Playgroud)
然后,更改Boolean为ScanResult第一个片段,然后返回new ScanResult(port, true)或new ScanResult(port, false)代替just true或false
编辑:实际上,我刚刚注意到:在这种特殊情况下,您不需要ScanResult类来保存结果+端口,并且仍然知道哪个端口是打开的.由于您将期货添加到已订购的List中,稍后,您按照添加它们的相同顺序处理它们,您可以拥有一个计数器,您可以在每次迭代时递增以知道您正在处理哪个端口.但是,嘿,这只是完整而准确的.不要尝试这样做,这太可怕了,我对此感到非常惭愧... 使用ScanResult对象更清晰,代码更容易阅读和维护,并允许您以后,例如,使用a 来改进扫描仪.CompletionService
小智 5
代码示例的灵感来自“Bruno Reis”
class PortScanner {
public static void main(final String... args) throws InterruptedException, ExecutionException {
final ExecutorService es = Executors.newFixedThreadPool(20);
final String ip = "127.0.0.1";
final int timeout = 200;
final List<Future<ScanResult>> futures = new ArrayList<>();
for (int port = 1; port <= 65535; port++) {
// for (int port = 1; port <= 80; port++) {
futures.add(portIsOpen(es, ip, port, timeout));
}
es.awaitTermination(200L, TimeUnit.MILLISECONDS);
int openPorts = 0;
for (final Future<ScanResult> f : futures) {
if (f.get().isOpen()) {
openPorts++;
System.out.println(f.get().getPort());
}
}
System.out.println("There are " + openPorts + " open ports on host " + ip + " (probed with a timeout of "
+ timeout + "ms)");
}
public static Future<ScanResult> portIsOpen(final ExecutorService es, final String ip, final int port,
final int timeout) {
return es.submit(new Callable<ScanResult>() {
@Override
public ScanResult call() {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), timeout);
socket.close();
return new ScanResult(port, true);
} catch (Exception ex) {
return new ScanResult(port, false);
}
}
});
}
public static class ScanResult {
private int port;
private boolean isOpen;
public ScanResult(int port, boolean isOpen) {
super();
this.port = port;
this.isOpen = isOpen;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public boolean isOpen() {
return isOpen;
}
public void setOpen(boolean isOpen) {
this.isOpen = isOpen;
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
51659 次 |
| 最近记录: |