네트워크 프린터 정보 수집을 위한 C++ 기반 다중 플랫폼 솔루션

다음은 시스템 API와 SNMP 프로토콜을 결합한 네트워크 프린터 정보 수집을 위한 크로스 플랫폼 C++ 구현입니다.

#include <iostream>
#include <vector>
#include <string>

// 플랫폼 추상화 레이어
#ifdef _WIN32
#include <windows.h>
#include <winsock.h>
#include <winprinter.h>
#elif defined(__linux__)
#include <cups/cups.h>
#endif

// SNMP 추상화 레이어
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>

struct DeviceInfo {
    std::string name;
    std::string ipAddress;
    std::string macAddress;
    std::string serialNumber;
    std::string manufacturer;
};

class NetworkPrinterScanner {
public:
    std::vector<DeviceInfo> scanPrinters() {
        std::vector<DeviceInfo> devices;

        // 기본 프린터 정보 가져오기
        #ifdef _WIN32
        listWindowsPrinters(devices);
        #elif defined(__linux__)
        listLinuxPrinters(devices);
        #endif

        // SNMP 사용하여 추가 정보 조회
        for (auto& device : devices) {
            if (!device.ipAddress.empty()) {
                fetchSNMPDetails(device);
            }
        }

        return devices;
    }

private:
    #ifdef _WIN32
    void listWindowsPrinters(std::vector<DeviceInfo>& devices) {
        DWORD required = 0, fetched = 0;
        EnumPrinters(PRINTER_ENUM_NETWORK, NULL, 4, NULL, 0, &required, &fetched);

        std::vector<BYTE> buffer(required);
        if (EnumPrinters(PRINTER_ENUM_NETWORK, NULL, 4, buffer.data(), 
                       buffer.size(), &required, &fetched)) {
            PRINTER_INFO_4* info = reinterpret_cast<PRINTER_INFO_4*>(buffer.data());
            for (DWORD i = 0; i < fetched; ++i) {
                DeviceInfo di;
                di.name = info[i].pPrinterName;
                parsePort(di);
                devices.push_back(di);
            }
        }
    }
    #elif defined(__linux__)
    void listLinuxPrinters(std::vector<DeviceInfo>& devices) {
        cups_dest_t* destinations = cupsGetDests(CUPS_HTTP_DEFAULT);
        for (int i = 0; i < cupsGetDests(&destinations); ++i) {
            DeviceInfo di;
            di.name = destinations[i].name;
            const char* uri = cupsGetOption("device-uri", 
                destinations[i].num_options, destinations[i].options);
            if (uri && strstr(uri, "socket://")) {
                di.ipAddress = extractIPAddress(uri);
            }
            devices.push_back(di);
        }
        cupsFreeDests(destinations);
    }
    #endif

    void fetchSNMPDetails(DeviceInfo& device) {
        retrieveSNMPData(device.ipAddress, "1.3.6.1.2.1.1.1.0", device.manufacturer);
        retrieveSNMPData(device.ipAddress, "1.3.6.1.2.1.43.5.1.1.17.1", device.serialNumber);

        std::string rawMac;
        if (retrieveSNMPData(device.ipAddress, "1.3.6.1.2.1.2.2.1.6.1", rawMac)) {
            device.macAddress = convertToMAC(rawMac);
        }
    }

    bool retrieveSNMPData(const std::string& ip, const char* oid, std::string& result) {
        // net-snmp 라이브러리 포함 필요
        // ...
        return true;
    }

    std::string convertToMAC(const std::string& hex) {
        std::string formatted;
        for (size_t i = 0; i < hex.length(); i += 2) {
            if (!formatted.empty()) formatted += ":";
            formatted += hex.substr(i, 2);
        }
        return formatted;
    }
};

int main() {
    NetworkPrinterScanner scanner;
    auto printers = scanner.scanPrinters();

    for (const auto& p : printers) {
        std::cout << "프린터: " << p.name << "\n"
                  << "  IP 주소: " << p.ipAddress << "\n"
                  << "  MAC 주소: " << p.macAddress << "\n"
                  << "  시리얼 번호: " << p.serialNumber << "\n"
                  << "  제조사: " << p.manufacturer << "\n\n";
    }
    return 0;
}

구현 설명

  1. 플랫폼 간 호환성:
  • Windows에서는 Win32 API를 통해 프린터 목록을 가져옵니다.
  • Linux에서는 CUPS API를 활용합니다.
  1. 정보 수집 절차:

graph TD A[시작] --> B[네트워크 프린터 검색] B --> C[기본 정보 수집] C --> D[IP 주소 파싱] D --> E[상세 정보 SNMP 요청] E --> F[결과 출력]

  1. 핵심 구성 요소:
  • 프린터 검색: 각 플랫폼의 네이티브 API를 통해 프린터 목록을 가져옵니다.
  • IP 주소 파싱: Windows는 포트 설정 분석, Linux는 CUPS 장치 URI 분석을 수행합니다.
  • SNMP 통신: net-snmp 라이브러리를 통해 상세 정보를 얻습니다.
  1. 플랫폼별 차이 처리:
기능 Windows 구현 Linux 구현
프린터 검색 EnumPrinters API cupsGetDests
IP 주소 파싱 등록표 포트 설정 분석 CUPS 장치 URI 분석
SNMP 통신 WinSNMP 또는 net-snmp net-snmp

컴파일 및 의존성

  • Windows 요구사항:

  • net-snmp Win32 개발 패키지 설치 필요

  • 링크된 라이브러리: wsnmp32.lib, winsock32.lib

  • Linux 요구사항:

sudo apt-get install libcups2-dev libsnmp-dev
  • 컴파일 명령어:
# Windows
cl /EHsc network_scanner.cpp /link wsnmp32.lib

# Linux
g++ -o network_scanner network_scanner.cpp -lcups -lnetsnmp

강화 제안

  • IP 주소 파싱 개선:
#ifdef _WIN32
void parsePort(DeviceInfo& info) {
    HKEY hKey;
    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
        "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Ports", 
        0, KEY_READ, &hKey) == ERROR_SUCCESS) {
        RegCloseKey(hKey);
    }
}
#endif
  • SNMP 오류 처리:
bool retrieveSNMPData(...) {
    try {
        // SNMP 로직 구현
        return true;
    } catch (const std::exception& e) {
        std::cerr << "SNMP 오류: " << e.what() << std::endl;
        return false;
    }
}
  • 제조사 OID 확장:
const std::map<std::string, std::string> VENDOR_OIDS = {
    {"HP", "1.3.6.1.4.1.11.2.3.9.1"},
    {"Canon", "1.3.6.1.4.1.1602.4.1.1.1"},
    {"Epson", "1.3.6.1.4.1.1248.1.1.1.1"}
};

주의 사항

  • 권한 요구사항:

  • Windows: 등록표에 접근하기 위해 관리자 권한 필요

  • Linux: cups 권한 및 SNMP 접근 권한 필요

  • 네트워크 구성:

  • 프린터의 SNMP 서비스가 활성화되어 있어야 함(UDP 161 포트)

  • 필요한 경우 SNMP 커뮤니티 문자열 설정 필요

태그: C++ snmp cups

8월 17일 02:13에 게시됨