• 文章
  • 簡單的埠掃描器
釋出
2013 年 4 月 16 日 (最後更新: 2013 年 4 月 17 日)

簡單的埠掃描器

評分: 4.3/5 (199 票)
*****

先決條件


簡介


埠掃描器是一個程式,它透過逐個埠嘗試連線伺服器來探測伺服器的開放埠。該程式通常會報告哪些埠是開放的,哪些是關閉的。更復雜的埠掃描器,如 Nmap,還可以探測其他資訊。埠掃描通常由系統管理員執行以驗證網路安全,或由攻擊者尋找開放埠以破壞伺服器安全。開放埠可能構成安全漏洞,因為它們允許遠端計算機連線。意外開放的埠可能表明惡意軟體正在監聽指令。

我的第一個埠掃描器


和之前一樣,掃描埠就像嘗試連線到地址和埠一樣簡單。如果連線嘗試成功,則埠必須是開放的。否則,則假定埠是關閉的。下面是一個使用 SFML 網路模組 (文件) 來檢查埠是否開放的示例函式。

1
2
3
4
5
6
7
bool port_is_open(const std::string& address, int port)
{
    sf::TcpSocket socket;
    bool open = (socket.connect(sf::IpAddress(address), port) == sf::Socket::Done);
    socket.disconnect();
    return open;
}


細分
  1. 首先,我們建立一個 sf::TcpSocket 例項 (文件),它允許我們連線到遠端套接字。
  2. 然後,我們連線套接字。透過呼叫 sf::IpAddress 的建構函式,我們將字串 'address' 轉換為 sf::IpAddress (文件) 例項。如果省略了顯式的建構函式呼叫,編譯器也會隱式執行。在嘗試連線後,我們透過將 sf::TcpSocket::connect 函式 (文件) 的返回值與列舉值 sf::Socket::Done (文件) 進行比較來檢查連線是否成功。如果兩者相等,則表示連線成功,埠是開放的。在這種情況下,變數 'open' 被設定為 true。
  3. 接下來,我們使用 sf::TcpSocket::disconnect 函式 (文件) 斷開套接字連線。如果我們省略了顯式呼叫,解構函式會自動完成此操作。
  4. 最後,我們將 'open' 的值返回給呼叫函式。
這實際上是我們唯一需要編寫的網路程式碼。我們也可以將其簡化為一行。
1
2
3
4
static bool port_is_open(const std::string& address, int port)
{
    return (sf::TcpSocket().connect(address, port) == sf::Socket::Done);
}

這裡我們建立了一個新的 sf::TcpSocket,連線到地址和埠,然後根據連線是否成功返回 true 或 false。我們去掉了不必要的顯式 sf::IpAddress 建構函式呼叫以及對 sf::TcpSocket::disconnect() 的呼叫。我們可以像這樣在程式中使用該函式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <SFML/Network.hpp>
#include <string>

static bool port_is_open(const std::string& address, int port)
{
    return (sf::TcpSocket().connect(address, port) == sf::Socket::Done);
}

int main()
{
    std::cout << "Port 80 : ";
    if (port_is_open("localhost", 80))
        std::cout << "OPEN" << std::endl;
    else
        std::cout << "CLOSED" << std::endl;
    return 0;
}
Port 80 : OPEN

嘗試編譯並執行此程式。它將測試您計算機上的 80 埠是否開放。請注意,“localhost”表示本地計算機;您也可以使用 IP 地址 127.0.0.1 或 ::1(IPv6 版本,儘管 SFML 尚不支援 IPv6)來實現相同目的。您可以將“localhost”更改為另一個網站的 IP 地址或 Web 地址(省略“http://”和任何路徑資訊),但請小心 - **未經許可掃描網站可能會在某些國家/地區給您帶來麻煩**,因為它可能被視為駭客行為。幸運的是,埠掃描器 Nmap 的網站有一個專門用於測試埠掃描器的頁面。嘗試將“localhost”更改為“scanme.nmap.org”。只是不要掃描太多次(頁面上說“每天幾次”)。

改進的埠掃描器


既然我們已經成功開發了一個可以掃描地址上埠的程式,我們就可以修改我們的程式,讓使用者指定要掃描的埠和地址。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <SFML/Network.hpp>
#include <string>

static bool port_is_open(const std::string& address, int port)
{
    return (sf::TcpSocket().connect(address, port) == sf::Socket::Done);
}


int main()
{
    std::string address;
    int port;
    // Get the address.
    std::cout << "Address: " << std::flush;
    std::getline(std::cin, address);
    // Get the port.
    std::cout << "Port: " << std::flush;
    std::cin >> port;
    // Scan!
    std::cout << "Scanning " << address << "...\n" << "Port " << port << " : ";
    if (port_is_open(address, port))
        std::cout << "OPEN" << std::endl;
    else
        std::cout << "CLOSED" << std::endl;
    return 0;
}
Address: 127.0.0.1
Port: 80
Scanning 127.0.0.1...
Port 80 : OPEN

請記住,127.0.0.1 等同於 localhost。另外,您的計算機上的 80 埠可能不開放。它只在我這裡開放,因為我執行的是 Apache HTTP 伺服器(80 埠是通常用於 HTTP,即網站的主要埠;另一個常用的 HTTP 埠是 8080)。

此外,我們也可以輕鬆地在 Nmap 的“ScanMe”頁面上測試此程式碼。
Address: scanme.nmap.org
Port: 80
Scanning scanme.nmap.org...
Port 80 : OPEN
這次可能需要一些時間,因為您不是掃描自己的計算機,而是透過 Internet 連線到另一臺計算機。

埠如雨後春筍


一次掃描一個埠很乏味,我們希望讓使用者掃描很多埠。一種方法是讓使用者輸入任意數量的埠,然後一次性掃描所有這些埠。這樣做的問題是使用者可能想掃描很多埠,而不得不一一輸入。我們也可以讓使用者指定一個埠範圍,例如 0-100,但那樣他們就無法指定該範圍之外的值。我們將做得更好,讓他們同時做到這兩點——在列表中指定範圍和單獨的埠,例如:“80,8080”;一個範圍,例如:“20-80”;或者一個包含範圍的列表:“20-80,8080”。此程式碼由於使用了模板、std::vector、std::stringstream 和 C++11 基於範圍的 for 迴圈而變得相當複雜,因此,如果您跳過了“先決條件”部分且不知道如何使用它們,請回到本文的頂部進行學習。否則,請繼續閱讀。

首先我們需要一個分割字串的函式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Splits a string into tokens arround a delimiter (default: space),
// optionally allowing empty tokens.
static std::vector<std::string> split(const std::string& string,
                                      char delimiter = ' ',
                                      bool allow_empty = false)
{
    std::vector<std::string> tokens;
    std::stringstream sstream(string);
    std::string token;
    while (std::getline(sstream, token, delimiter)) {
        if (allow_empty || token.size() > 0)
            tokens.push_back(token);
    }
    return tokens;
}


埠的資料型別將是字串,但我們想要整數,所以我們還需要一個將字串轉換為整數的函式。
1
2
3
4
5
6
7
8
// Converts a string to an integer.
static int string_to_int(const std::string& string)
{
    std::stringstream sstream(string);
    int i;
    sstream >> i;
    return i;
}


如果我們有一個埠範圍,我們將需要一個函式來生成該範圍內的所有值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Swaps two values.
template <typename T>
static void swap(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}

// Generates a vector containing a range of values.
template <typename T>
static std::vector<T> range(T min, T max)
{
    if (min > max)
        swap(min, max);
    if (min == max)
        return std::vector<T>(1, min);
    std::vector<T> values;
    for (; min <= max; ++min)
        values.push_back(min);
    return values;
}


最後,我們需要一個函式來使用上述函式實際解析埠列表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Parses a list of ports containing numbers and ranges
static std::vector<int> parse_ports_list(const std::string& list)
{
    std::vector<int> ports;
    // Split list items.
    for (const std::string& token : split(list, ',')) {
        // Split ranges.
        std::vector<std::string> strrange = split(token, '-');
        switch (strrange.size()) {
            // Only one value (add to end of 'ports').
            case 0: ports.push_back(string_to_int(token));       break;
            case 1: ports.push_back(string_to_int(strrange[0])); break;
            // Two values (range - add everything in that range).
            case 2:
            {
                int min = string_to_int(strrange[0]),
                    max = string_to_int(strrange[1]);
                for (int port : range(min, max))
                    ports.push_back(port);
                break;
            }
            default:
                break;
        }
    }
    return ports;
}


我們的最終程式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#include <iostream>
#include <SFML/Network.hpp>
#include <sstream>
#include <string>
#include <vector>

static bool port_is_open(const std::string& address, int port)
{
    return (sf::TcpSocket().connect(address, port) == sf::Socket::Done);
}


static std::vector<std::string> split(const std::string& string,
                                      char delimiter = ' ',
                                      bool allow_empty = false)
{
    std::vector<std::string> tokens;
    std::stringstream sstream(string);
    std::string token;
    while (std::getline(sstream, token, delimiter)) {
        if (allow_empty || token.size() > 0)
            tokens.push_back(token);
    }
    return tokens;
}

static int string_to_int(const std::string& string)
{
    std::stringstream sstream(string);
    int i;
    sstream >> i;
    return i;
}

template <typename T>
static void swap(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}

template <typename T>
static std::vector<T> range(T min, T max)
{
    if (min > max)
        swap(min, max);
    if (min == max)
        return std::vector<T>(1, min);
    std::vector<T> values;
    for (; min <= max; ++min)
        values.push_back(min);
    return values;
}

static std::vector<int> parse_ports_list(const std::string& list)
{
    std::vector<int> ports;
    for (const std::string& token : split(list, ',')) {
        std::vector<std::string> strrange = split(token, '-');
        switch (strrange.size()) {
            case 0: ports.push_back(string_to_int(token));       break;
            case 1: ports.push_back(string_to_int(strrange[0])); break;
            case 2:
            {
                int min = string_to_int(strrange[0]),
                    max = string_to_int(strrange[1]);
                for (int port : range(min, max))
                    ports.push_back(port);
                break;
            }
            default:
                break;
        }
    }
    return ports;
}

int main()
{
    std::string address;
    std::string port_list;
    std::vector<int> ports;
    std::cout << "Address: " << std::flush;
    std::getline(std::cin, address);
    std::cout << "Port: " << std::flush;
    std::getline(std::cin, port_list);
    ports = parse_ports_list(port_list);
    std::cout << "Scanning " << address << "...\n";
    for (int port : ports) {
        std::cout << "Port " << port << " : ";
        if (port_is_open(address, port))
            std::cout << "OPEN\n";
        else
            std::cout << "CLOSED\n";
    }
    std::cout << std::flush;
    return 0;
}
Address: 127.0.0.1
Port: 20-80,8080
Scanning 127.0.0.1...
Port 20 : CLOSED
Port 21 : CLOSED
Port 22 : OPEN
Port 23 : CLOSED
Port 24 : CLOSED
Port 25 : CLOSED
Port 26 : CLOSED
Port 27 : CLOSED
Port 28 : CLOSED
Port 29 : CLOSED
Port 30 : CLOSED
Port 31 : CLOSED
Port 32 : CLOSED
Port 33 : CLOSED
Port 34 : CLOSED
Port 35 : CLOSED
Port 36 : CLOSED
Port 37 : CLOSED
Port 38 : CLOSED
Port 39 : CLOSED
Port 40 : CLOSED
Port 41 : CLOSED
Port 42 : CLOSED
Port 43 : CLOSED
Port 44 : CLOSED
Port 45 : CLOSED
Port 46 : CLOSED
Port 47 : CLOSED
Port 48 : CLOSED
Port 49 : CLOSED
Port 50 : CLOSED
Port 51 : CLOSED
Port 52 : CLOSED
Port 53 : OPEN
Port 54 : CLOSED
Port 55 : CLOSED
Port 56 : CLOSED
Port 57 : CLOSED
Port 58 : CLOSED
Port 59 : CLOSED
Port 60 : CLOSED
Port 61 : CLOSED
Port 62 : CLOSED
Port 63 : CLOSED
Port 64 : CLOSED
Port 65 : CLOSED
Port 66 : CLOSED
Port 67 : CLOSED
Port 68 : CLOSED
Port 69 : CLOSED
Port 70 : CLOSED
Port 71 : CLOSED
Port 72 : CLOSED
Port 73 : CLOSED
Port 74 : CLOSED
Port 75 : CLOSED
Port 76 : CLOSED
Port 77 : CLOSED
Port 78 : CLOSED
Port 79 : CLOSED
Port 80 : OPEN
Port 8080 : CLOSED

就這樣!我們現在有了一個成功的埠掃描器,它可以掃描使用者所需的任意數量的埠。

再掃描幾個埠


我們可以透過更改以下程式碼來修改我們的程式,使其不顯示關閉的埠:
89
90
91
92
93
94
95
96
    std::cout << "Scanning " << address << "...\n";
    for (int port : ports) {
        std::cout << "Port " << port << " : ";
        if (port_is_open(address, port))
            std::cout << "OPEN\n";
        else
            std::cout << "CLOSED\n";
    }


89
90
91
92
93
    std::cout << "Showing open ports on " << address << "...\n";
    for (int port : ports) {
        if (port_is_open(address, port))
            std::cout << "Port " << port << " : OPEN\n";
    }

這使得輸出更加清晰。掃描我計算機上的所有埠。
Address: localhost
Port: 0-65535
Showing open ports on localhost...
Port 22 : OPEN
Port 53 : OPEN
Port 80 : OPEN
Port 139 : OPEN
Port 445 : OPEN
Port 631 : OPEN
Port 3306 : OPEN
Port 17500 : OPEN
請注意,共有 65535 個埠。如果我們使用先前版本的埠掃描器掃描所有埠,它將生成 65,535 行輸出,這將使得獲取所需資訊非常困難。

我們可以透過在檔案頂部新增 #include <iomanip> ,在主函式中的 for 迴圈之前新增 size_t width = digits(maximum(ports));,然後更改顯示埠狀態的行以 std::cout << "Port " << std::setw(width) << port << " : OPEN\n"; 來漂亮地格式化我們的輸出。您還需要在 main 函式之前新增這兩個函式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Gets the maximum value in a vector.
template <typename T>
static T maximum(const std::vector<T>& values)
{
    T max = values[0];
    for (T value : values) {
        if (value > max)
            max = value;
    }
    return max;
}

// Counts the digits in a number.
template <typename T>
static size_t digits(T value)
{
    size_t count = (value < 0) ? 1 : 0;
    if (value == 0)
        return 0;
    while (value) {
        value /= 10;
        ++count;
    };
    return count;
}


現在輸出將得到很好的格式化。
Address: localhost
Port: 0-65535
Showing open ports on localhost...
Port    22 : OPEN
Port    53 : OPEN
Port    80 : OPEN
Port   139 : OPEN
Port   445 : OPEN
Port   631 : OPEN
Port  3306 : OPEN
Port 17500 : OPEN
Port 35723 : OPEN
Port 43351 : OPEN

這是我們改進的埠掃描器的程式碼。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <SFML/Network.hpp>
#include <sstream>
#include <string>
#include <vector>

static bool port_is_open(const std::string& address, int port)
{
    return (sf::SocketTCP().connect(address, port) == sf::Socket::Done);
}

static std::vector<std::string> split(const std::string& string,
                                      char delimiter = ' ',
                                      bool allow_empty = false)
{
    std::vector<std::string> tokens;
    std::stringstream sstream(string);
    std::string token;
    while (std::getline(sstream, token, delimiter)) {
        if (allow_empty || token.size() > 0)
            tokens.push_back(token);
    }
    return tokens;
}

static int string_to_int(const std::string& string)
{
    std::stringstream sstream(string);
    int i;
    sstream >> i;
    return i;
}

template <typename T>
static void swap(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}

template <typename T>
static std::vector<T> range(T min, T max)
{
    if (min > max)
        swap(min, max);
    if (min == max)
        return std::vector<T>(1, min);
    std::vector<T> values;
    for (; min <= max; ++min)
        values.push_back(min);
    return values;
}

static std::vector<int> parse_ports_list(const std::string& list)
{
    std::vector<int> ports;
    for (const std::string& token : split(list, ',')) {
        std::vector<std::string> strrange = split(token, '-');
        switch (strrange.size()) {
            case 0: ports.push_back(string_to_int(token));       break;
            case 1: ports.push_back(string_to_int(strrange[0])); break;
            case 2:
            {
                int min = string_to_int(strrange[0]),
                    max = string_to_int(strrange[1]);
                for (int port : range(min, max))
                    ports.push_back(port);
                break;
            }
            default:
                break;
        }
    }
    return ports;
}

template <typename T>
static T maximum(const std::vector<T>& values)
{
    T max = values[0];
    for (T value : values) {
        if (value > max)
            max = value;
    }
    return max;
}

template <typename T>
static size_t digits(T value)
{
    size_t count = (value < 0) ? 1 : 0;
    if (value == 0)
        return 0;
    while (value) {
        value /= 10;
        ++count;
    };
    return count;
}

int main()
{
    std::string address;
    std::string port_list;
    std::vector<int> ports;
    std::cout << "Address: " << std::flush;
    std::getline(std::cin, address);
    std::cout << "Port: " << std::flush;
    std::getline(std::cin, port_list);
    ports = parse_ports_list(port_list);
    std::cout << "Showing open ports on " << address << "...\n";
    size_t width = digits(maximum(ports));
    for (int port : ports) {
        if (port_is_open(address, port))
            std::cout << "Port " << std::setw(width) << port << " : OPEN\n";
    }
    std::cout << std::flush;
    return 0;
}


您可能希望能夠輕鬆地在指令碼中使用該程式,並從其他程式輕鬆執行它,在這種情況下,您可以修改它以使用命令列來獲取地址和埠資訊。下面是一個修改後的 main 函式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
int main(int argc, char* argv[])
{
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " address port(s)\n"
                  << "Examples:\n"
                  << "\t" << argv[0] << " 127.0.0.1 80\n"
                  << "\t" << argv[0] << " localhost 80,8080\n"
                  << "\t" << argv[0] << " 192.0.43.10 0-65535\n"
                  << "\t" << argv[0] << " example.com 0-21,80,8080"
                  << std::endl;
        std::exit(EXIT_FAILURE);
    }
    std::string address = argv[1];
    std::vector<int> ports = parse_ports_list(std::string(argv[2]));
    std::cout << "Showing open ports on " << address << "...\n";
    size_t width = digits(maximum(ports));
    for (int port : ports) {
        if (port_is_open(address, port))
            std::cout << "Port " << std::setw(width) << port << " : OPEN\";
    }
    std::cout << std::endl;
    return 0;
} 


下面是一個允許兩者同時使用的版本。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main(int argc, char* argv[])
{
    std::string address;
    std::vector<int> ports;
    if (argc == 3) {
        address = argv[1];
        ports = parse_ports_list(std::string(argv[2]));
    } else {
        std::string port_list;
        std::cout << "Address: " << std::flush;
        std::getline(std::cin, address);
        std::cout << "Port: " << std::flush;
        std::getline(std::cin, port_list);
        ports = parse_ports_list(port_list);
    }
    std::cout << "Showing open ports on " << address << "...\n";
    size_t width = digits(maximum(ports));
    for (int port : ports) {
        if (port_is_open(address, port))
            std::cout << "Port " << std::setw(width) << port << " : OPEN\n";
    }
    std::cout << std::flush;
    return 0;
}


這是埠掃描器的最終(目前)版本,它允許命令列和互動式呼叫。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <cstdlib>
#include <iomanip>
#include <iostream>
#include <SFML/Network.hpp>
#include <sstream>
#include <string>
#include <vector>

static bool port_is_open(const std::string& address, int port)
{
    return (sf::SocketTCP().connect(address, port) == sf::Socket::Done);
}

static std::vector<std::string> split(const std::string& string,
                                      char delimiter = ' ',
                                      bool allow_empty = false)
{
    std::vector<std::string> tokens;
    std::stringstream sstream(string);
    std::string token;
    while (std::getline(sstream, token, delimiter)) {
        if (allow_empty || token.size() > 0)
            tokens.push_back(token);
    }
    return tokens;
}

static int string_to_int(const std::string& string)
{
    std::stringstream sstream(string);
    int i;
    sstream >> i;
    return i;
}

template <typename T>
static void swap(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}

template <typename T>
static std::vector<T> range(T min, T max)
{
    if (min > max)
        swap(min, max);
    if (min == max)
        return std::vector<T>(1, min);
    std::vector<T> values;
    for (; min <= max; ++min)
        values.push_back(min);
    return values;
}

static std::vector<int> parse_ports_list(const std::string& list)
{
    std::vector<int> ports;
    for (const std::string& token : split(list, ',')) {
        std::vector<std::string> strrange = split(token, '-');
        switch (strrange.size()) {
            case 0: ports.push_back(string_to_int(token));       break;
            case 1: ports.push_back(string_to_int(strrange[0])); break;
            case 2:
            {
                int min = string_to_int(strrange[0]),
                    max = string_to_int(strrange[1]);
                for (int port : range(min, max))
                    ports.push_back(port);
                break;
            }
            default:
                break;
        }
    }
    return ports;
}

template <typename T>
static T maximum(const std::vector<T>& values)
{
    T max = values[0];
    for (T value : values) {
        if (value > max)
            max = value;
    }
    return max;
}

template <typename T>
static size_t digits(T value)
{
    size_t count = (value < 0) ? 1 : 0;
    if (value == 0)
        return 0;
    while (value) {
        value /= 10;
        ++count;
    };
    return count;
}

int main(int argc, char* argv[])
{
    std::string address;
    std::vector<int> ports;
    if (argc == 3) {
        address = argv[1];
        ports = parse_ports_list(std::string(argv[2]));
    } else {
        std::string port_list;
        std::cout << "Address: " << std::flush;
        std::getline(std::cin, address);
        std::cout << "Port: " << std::flush;
        std::getline(std::cin, port_list);
        ports = parse_ports_list(port_list);
    }
    std::cout << "Showing open ports on " << address << "...\n";
    size_t width = digits(maximum(ports));
    for (int port : ports) {
        if (port_is_open(address, port))
            std::cout << "Port " << std::setw(width) << port << " : OPEN\n";
    }
    std::cout << std::flush;
    return 0;
}


隨意出於任何目的使用或修改以上所有程式碼(免責宣告:對於使用我的程式碼執行的任何惡意行為,我概不負責)。

您可以找到我編寫的原始程式的原始碼,該程式在編寫本文時演變成了上述程式碼。該程式是在 FreeBSD 許可下分發的。

待辦事項

附件:[cppscan.cpp] [cppscan.h] [main.cpp]