다음은 시스템 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;
}
구현 설명
- 플랫폼 간 호환성:
- Windows에서는 Win32 API를 통해 프린터 목록을 가져옵니다.
- Linux에서는 CUPS API를 활용합니다.
- 정보 수집 절차:
graph TD A[시작] --> B[네트워크 프린터 검색] B --> C[기본 정보 수집] C --> D[IP 주소 파싱] D --> E[상세 정보 SNMP 요청] E --> F[결과 출력]
- 핵심 구성 요소:
- 프린터 검색: 각 플랫폼의 네이티브 API를 통해 프린터 목록을 가져옵니다.
- IP 주소 파싱: Windows는 포트 설정 분석, Linux는 CUPS 장치 URI 분석을 수행합니다.
- SNMP 통신: net-snmp 라이브러리를 통해 상세 정보를 얻습니다.
- 플랫폼별 차이 처리:
| 기능 | 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 커뮤니티 문자열 설정 필요