2017-12-20 30 views
-2

IP 범위가 주어진 열린 포트를 검색해야하는 C#에서 간단하게 포트 스캐너를 만들고 있습니다. 아래에서 볼 수 있듯이 나는 코드의 대부분에 async/awaitTask을 사용하고 있습니다 :단일 작업 대리스트 <Task> in C#

internal class PortScanner 
{ 
    private IPAddress host; 
    private int startPort; 
    private int endPort; 

    private const int PORT_MIN_VALUE = 1; 
    private const int PORT_MAX_VALUE = 65535; 

    public PortScanner(IPAddress host, int portStart, int portStop) 
    { 
     this.host = host; 
     this.startPort = portStart; 
     this.endPort = portStop; 
    } 

    public PortScanner(IPAddress host) 
     : this(host, PORT_MIN_VALUE, PORT_MIN_VALUE) 
    { 
    } 

    private async Task<bool> IsPortOpen(int port) 
    { 
     Socket socket = null; 

     try 
     { 
      // make a TCP based socket 
      socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

      // connect 
      await Task.Run(() => socket.Connect(this.host, port)); 

      return true; 
     } 
     catch (SocketException ex) 
     { 
      if (ex.SocketErrorCode == SocketError.ConnectionRefused) 
      { 
       return false; 
      } 
     } 
     finally 
     { 
      if (socket?.Connected ?? false) 
      { 
       socket?.Disconnect(false); 
      } 
      socket?.Close(); 
     } 

     return false; 
    } 

    private async Task CheckPort(int port) 
    { 
     if (await IsPortOpen(port)) 
     { 
      Console.WriteLine("Host: {0} - Port: {1} is open.", this.host.ToString(), port.ToString()); 
     } 
    } 

    public async Task Scan() 
    { 
     Console.WriteLine("Scanning for {0}", this.host); 
     for (int port = this.startPort; port <= this.endPort; port++) 
     { 
      await CheckPort(port); 
     } 
    } 
} 

이제 지점입니다 그 Main 기능에,이 같은 단일 Task를 사용하는 경우 :

try 
{ 
    PortScanner ps = new PortScanner(ipsInRange.Begin, 15, 25); 
    var task = ps.Scan(); 
    task.Wait(); 
} 
catch (Exception ex) 
{ 
    Console.WriteLine(ex); 
} 
나는 우리가하려고 할 때,

Scanning for 192.168.1.1 
Host: 192.168.1.1 - Port: 21 is open. 
Host: 192.168.1.1 - Port: 23 is open. 

을하지만 :

는 내가 같은 출력을 얻을 의미에서 잘 작동 (그리고 그것을 완료하는 데 몇 초 정도 걸립니다) 이와 같은 전자 List<Task>은 :

Scanning for 192.168.1.3 
Scanning for 192.168.1.2 
Scanning for 192.168.1.1 
Scanning for 192.168.1.4 
Scanning for 192.168.1.5 

그래서, 기본적으로 검사하지 않는 것 :

foreach (var set in setOfIPs) 
{ 
    List<Task> scanTasks = new List<Task>(set.Count()); 

    foreach (var ip in set) 
    { 
     scanTasks.Add(Task.Factory.StartNew(async() => 
     { 
      PortScanner ps = new PortScanner(ip, 15, 25); 
      await ps.Scan(); 
     })); 
    } 

    Task.WaitAll(scanTasks.ToArray()); 
} 

내가 출력으로 얻을 것은이 (프로그램이 즉시 일초에서 완료) 단순히 각 포트는 열려있는 포트를 인쇄하지 않으므로 별도로 설치해야합니다. 어떤 아이디어가 문제 일 수 있으며 Task 번을 List<Task> 안에 여러 번 호출 할 수 있습니까?

+4

당신이해야 질문을 삭제하고 다시 게시하지 마십시오. https://stackoverflow.com/questions/47912486/data-parallelism-and-threads-in-c-sharp – Servy

+1

@Servy 아마도 문제를 좁혀 야 할 것입니다. 그것을 더 명백하게했다. – typos

+1

질문을 명확하게하려면 질문을 편집하고 삭제하고 다시 게시하지 말아야합니다. – Servy

답변

1

이것은 전통적인 트랩이며 Task.Factory.StartNew입니다. 메서드는 Task<T>을 반환합니다. T이 콜백의 반환 유형입니다. 귀하의 람다는 비동기이며 따라서 작업을 반환합니다. 함께 작업하면 Task<Task>으로 끝나고 내부 작업을 기다리는 동안 외부 작업을 기다리고 있습니다.

두 솔루션 :

  1. 권장 하나를 대신 Task.Factory.StartNewTask.Run를 사용합니다. 이는 일반적인 권장 사항이며 올바른 해결책이 아닌 한 Task.Factory.StartNew을 사용해서는 안됩니다. Task.Run은 실행 한 것과 같은 많은 함정을 피합니다. 당신이 이제까지 Task.Factory.StartNew를 사용하는 정당한 이유가있는 경우

    scanTasks.Add(Task.Run(async() => 
    { 
        PortScanner ps = new PortScanner(ip, 15, 25); 
        await ps.Scan(); 
    })); 
    
  2. 는, 당신은 내부 하나를 기다릴 수 있도록 작업에 .Unwrap() 방법을 사용할 수 있습니다 :

    scanTasks.Add(Task.Factory.StartNew(async() => 
    { 
        PortScanner ps = new PortScanner(ip, 15, 25); 
        await ps.Scan(); 
    }).Unwrap()); 
    
+0

대단히 감사합니다. 이것은 문제를 해결했으며, 이제는 문제가 무엇인지 이해했습니다. 'Task.Factory.StartNew'가 적절한 선택 일 때 어떤 특별한 가이드 라인이 있습니까? – typos

+0

@typos 글쎄요, 긴 이야기가 짧습니다 :'Task.Run'으로는 할 수없는 일을하고 싶다면 (스스로 질문을한다면,'Task.Factory.StartNew'가 필요 없다는 뜻입니다.).좀더 구체적으로 말하자면, 커스텀 태스크 스케줄러와 태스크의 플래그 ('LongRunning' 또는'PreferFairness')를 설정할 수 있습니다. –