网络打印机的搜索与连接(一)

介绍

        网络打印机就是可以通过网络连接上的打印机,这类打印机分2种:自身具有互联网接入功能可以分配IP的打印机我们称为网络打印机、另外一种就是被某台电脑连接上去后通过共享的方式共享到网络里面的我们称为共享打印机。现在还有一种可以通过互联网连接的网络打印机,本篇文章暂时先不讲。下面将详细讲解上述2类打印机的搜索、连接。

网络打印机的搜索

        网络打印机可以通过2种协议搜索到

  • snmp协议:此协议适用于查询单个IP的网络打印机搜索。此协议会发送一个标准的snmp协议内容给目标ip地址(协议内容:".1.3.6.1.2.1.1.1.0"),如果该ip是某个网络打印机那么就会进行应答(回答内容:SNMPv2-MIB::sysDescr.0 = STRING: HP ETHERNET MULTI-ENVIRONMENT,SN:VNH3626885,FN:3K90LKC,SVCID:34305,PID:HP LaserJet MFP M227fdn)。 代码如下:
// 初始化SNMP库。
init_snmp("snmp_printer");

struct snmp_session session;
struct snmp_session* sess_handle = nullptr;
struct snmp_pdu* pdu = nullptr;
struct snmp_pdu* response = nullptr;
struct variable_list* variables = nullptr;
oid id_oid[MAX_OID_LEN];
size_t id_len = MAX_OID_LEN;
int status;

// 初始化会话
snmp_sess_init(&session);
session.peername = _strdup(peername);

// 设置社区字符串
session.community = (u_char*)_strdup("public");
session.community_len = strlen((const char*)session.community);

// 设置SNMP版本
session.version = SNMP_VERSION_2c;
session.timeout = 1000;
session.retries = 1;

// 打开SNMP会话
sess_handle = snmp_open(&session);
if (!sess_handle) 
{
    snmp_perror("snmp_open");
    return;
}

// 创建 PDU
pdu = snmp_pdu_create(SNMP_MSG_GET);
if (pdu == nullptr)
{
    return;
}

read_objid(".1.3.6.1.2.1.1.1.0", id_oid, &id_len);
snmp_add_null_var(pdu, id_oid, id_len);

// 发送 PDU
status = snmp_synch_response(sess_handle, pdu, &response);

// 检查是否成功
if (status == STAT_SUCCESS && response->errstat == SNMP_ERR_NOERROR)
{
    // 处理变量列表
    for (variables = response->variables; variables; variables = variables->next_variable)
    {
        snprint_variable(szPrinterInfo, nBuffSize, variables->name, variables->name_length, variables);
    }
    KLOG_INFO << "QueryPrinter SnmpGet: " << szPrinterInfo;
}
else 
{
    // 如果失败,则打印错误
    if (status == STAT_SUCCESS)
        fprintf(stderr, "Error in packet\nReason: %s\n",
            snmp_errstring(response->errstat));
    else if (status == STAT_TIMEOUT)
        fprintf(stderr, "Timeout: No response from %s.\n",
            session.peername);
    else
        snmp_sess_perror("snmpdemoapp", sess_handle);
}

// 释放响应
if (response && pdu) {
    snmp_free_pdu(response);
}

// 关闭会话
snmp_close(sess_handle);

// 清理SNMP库。
snmp_shutdown("snmp_printer");
  • mDNS多播DNS协议来解析网络上设备的主机名到IP地址,而无需中央DNS服务器的网络服务协议。通过向固定IP和和固定端口5353发送不同的协议来接收应答这样的方式搜索打印机
    static int mdns_query_send(int sock, mdns_record_type_t type, const char* name, size_t length, void* buffer,size_t capacity, uint16_t query_id) 
{
        if (capacity < (17 + length))
            return -1;

        uint16_t rclass = MDNS_CLASS_IN | MDNS_UNICAST_RESPONSE;

        struct sockaddr_storage addr_storage;
        struct sockaddr* saddr = (struct sockaddr*)&addr_storage;
        socklen_t saddrlen = sizeof(addr_storage);
        if (getsockname(sock, saddr, &saddrlen) == 0) {
            if ((saddr->sa_family == AF_INET) &&
                (ntohs(((struct sockaddr_in*)saddr)->sin_port) == MDNS_PORT))
                rclass &= ~MDNS_UNICAST_RESPONSE;
            else if ((saddr->sa_family == AF_INET6) &&
                (ntohs(((struct sockaddr_in6*)saddr)->sin6_port) == MDNS_PORT))
                rclass &= ~MDNS_UNICAST_RESPONSE;
        }

        uint16_t* data = (uint16_t*)buffer;
        // Query ID
        *data++ = htons(query_id);
        // Flags
        *data++ = 0;
        // Questions
        *data++ = htons(1);
        // No answer, authority or additional RRs
        *data++ = 0;
        *data++ = 0;
        *data++ = 0;
        // Fill in question
        // Name string
        data = (uint16_t*)mdns_string_make(data, capacity - 17, name, length);
        if (!data)
            return -1;
        // Record type
        *data++ = htons(type);
        //! Optional unicast response based on local port, class IN
        *data++ = htons(rclass);

        ptrdiff_t tosend = (char*)data - (char*)buffer;
        if (mdns_multicast_send(sock, buffer, (size_t)tosend))
            return -1;
        return query_id;
    }

    static size_t
        mdns_query_recv(int sock, void* buffer, size_t capacity, mdns_record_callback_fn callback,
            void* user_data, int only_query_id) {
        struct sockaddr_in6 addr;
        struct sockaddr* saddr = (struct sockaddr*)&addr;
        socklen_t addrlen = sizeof(addr);
        memset(&addr, 0, sizeof(addr));
        int ret = recvfrom(sock, (char*)buffer, (mdns_size_t)capacity, 0, saddr, &addrlen);
        if (ret <= 0)
            return 0;

        size_t data_size = (size_t)ret;
        uint16_t* data = (uint16_t*)buffer;

        uint16_t query_id = ntohs(*data++);
        uint16_t flags = ntohs(*data++);
        uint16_t questions = ntohs(*data++);
        uint16_t answer_rrs = ntohs(*data++);
        uint16_t authority_rrs = ntohs(*data++);
        uint16_t additional_rrs = ntohs(*data++);
        (void)sizeof(flags);

        if ((only_query_id > 0) && (query_id != only_query_id))
            return 0;  // Not a reply to the wanted one-shot query

        if (questions > 1)
            return 0;

        // Skip questions part
        int i;
        for (i = 0; i < questions; ++i) {
            size_t ofs = (size_t)((char*)data - (char*)buffer);
            if (!mdns_string_skip(buffer, data_size, &ofs))
                return 0;
            data = (uint16_t*)((char*)buffer + ofs);
            uint16_t rtype = ntohs(*data++);
            uint16_t rclass = ntohs(*data++);
            (void)sizeof(rtype);
            (void)sizeof(rclass);
        }

        size_t records = 0;
        size_t offset = MDNS_POINTER_DIFF(data, buffer);
        records += mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
            MDNS_ENTRYTYPE_ANSWER, query_id, answer_rrs, callback, user_data);
        records +=
            mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
                MDNS_ENTRYTYPE_AUTHORITY, query_id, authority_rrs, callback, user_data);
        records += mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
            MDNS_ENTRYTYPE_ADDITIONAL, query_id, additional_rrs, callback,
            user_data);
        return records;
    }

共享打印机的搜索

        共享打印机的搜索其实是根据windows的远程登录原理来实现,首先利用Guest帐号登录远程系统,然后再遍历设备获取打印机。 代码如下:

void CSharedPrinter::SearchSharedPrinter(const char* szIpAddress, const char* szUser, const char* szPassword, bool bDefaultLogin, bool bNotifyUI)
{
    m_strSharedUser = szUser;
    m_strSharedPass = szPassword;
    std::wstring strIpAddress = cf::string::SysMultiByteToWide(szIpAddress, CP_ACP);
    std::wstring strUser = cf::string::SysMultiByteToWide(szUser, CP_ACP);
    std::wstring strPassword = cf::string::SysMultiByteToWide(szPassword, CP_ACP);

    wchar_t remote[MAX_PATH] = { 0 };
    _snwprintf_s(remote, MAX_PATH, L"\\\\%s\\IPC$", strIpAddress.c_str());
    USE_INFO_2 useInfo;
    ZeroMemory(&useInfo, sizeof(useInfo));
    useInfo.ui2_local = nullptr;
    useInfo.ui2_remote = remote;
    useInfo.ui2_username = (LPWSTR)strUser.c_str();
    useInfo.ui2_password = (LPWSTR)strPassword.c_str();
    useInfo.ui2_domainname = (LPWSTR)L"";
    useInfo.ui2_asg_type = USE_WILDCARD;

    int nRetry = 0;
LOGIN:
    // 建立连接
    nRetry++;
    DWORD dwResult;
    NET_API_STATUS nStatus = NetUseAdd(NULL, 2, (LPBYTE)&useInfo, &dwResult);
    if (nStatus != NERR_Success)
    {
        if (bNotifyUI)
        {
            if (OnLoginError(nStatus, szIpAddress, szUser, szPassword, bDefaultLogin))
            {
                // 修复重复,重试一次
                if (nRetry < 2 && !m_bStopAddressSearch)
                {
                    goto LOGIN;
                }
            }
        }

        return;
    }

    if (bNotifyUI)
    {
        PrinterConnect data;
        data.nAction = 2;
        data.emPrinterType = PrinterType::share;
        data.nLoginResult = 1;
        KReportInfoC::reportPrinterConnect(data);
    }

    LPBYTE pBuf = nullptr;
    DWORD entriesRead = 0;
    DWORD totalEntries = 0;
    DWORD resumeHandle = 0;
    wchar_t remote2[MAX_PATH] = { 0 };
    _snwprintf_s(remote2, MAX_PATH, L"\\\\%s", strIpAddress.c_str());
    nStatus = NetShareEnum(remote2, 1, &pBuf, MAX_PREFERRED_LENGTH, &entriesRead, &totalEntries, &resumeHandle);
    if (nStatus == ERROR_SUCCESS || nStatus == ERROR_MORE_DATA)
    {
        PSHARE_INFO_1 pShareInfo = reinterpret_cast<PSHARE_INFO_1>(pBuf);

        for (DWORD i = 0; i < entriesRead; i++)
        {
            if (STYPE_PRINTQ == pShareInfo[i].shi1_type)
            {
                auto strName = cf::string::SysWideToMultiByte(pShareInfo[i].shi1_netname, CP_UTF8);
                NetworkPrinter stPrinterInfo;
                strcpy_s(stPrinterInfo.szName, strName.c_str());
                strcpy_s(stPrinterInfo.szIPV4, szIpAddress);
                stPrinterInfo.bPrinter = true;
                NotifySearchResult(szIpAddress, stPrinterInfo, PRINTER_TYPE::PRINTER_SHARED, false);
            }
        }

        m_LoginInfo[szIpAddress] = std::make_pair(szUser,szPassword);
    }

    NetUseDel(nullptr, remote, USE_NOFORCE);
    if (pBuf != nullptr)
    {
        NetApiBufferFree(pBuf);
    }
}

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/958094.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c++算法贪心系列

本篇文章&#xff0c;同大家一起学习贪心算法&#xff01;&#xff01;&#xff01; 第一题 题目链接 2208. 将数组和减半的最少操作次数 - 力扣&#xff08;LeetCode&#xff09; 题目解析 本题重点&#xff1a;最终的数组和要小于原数组和的一半&#xff0c;且求这一操作的…

NewStar CTF week1 web wp

谢谢皮蛋 做这题之前需要先去学习一些数据库的知识 1 order by 2 1可以理解为输入的id&#xff0c;是一个占位符&#xff0c;按第二列排序用来测试列数&#xff0c;如果没有两列则会报错-1 union select 1,2 -1同样是占位符&#xff0c;union的作用是将注入语句合并到原始语句…

【2025小年源码免费送】

&#x1f496;学习知识需费心&#xff0c; &#x1f4d5;整理归纳更费神。 &#x1f389;源码免费人人喜&#xff0c; &#x1f525;码农福利等你领&#xff01; &#x1f496;山高路远坑又深&#xff0c; &#x1f4d5;大军纵横任驰奔&#xff0c; &#x1f389;谁敢横刀立马行…

在Qt中实现点击一个界面上的按钮弹窗到另一个界面

文章目录 步骤 1&#xff1a;创建新窗口类步骤 2&#xff1a;设计窗口的 UI步骤 3&#xff1a;设计响应函数 以下是一个完整的示例&#xff0c;展示在Qt中如何实现在一个窗口中通过点击按钮弹出一个新窗口。 步骤 1&#xff1a;创建新窗口类 假设你要创建一个名为 WelcomeWidg…

基于AutoDL云计算平台+LLaMA-Factory训练平台微调本地大模型

1. 注册与认证 访问AutoDL官网&#xff1a;前往 AutoDL官网。 注册账号&#xff1a;完成注册流程。 实名认证&#xff1a;按照要求完成实名认证&#xff0c;以确保账号的合规性。 2. 选择GPU资源 进入算力市场&#xff1a;在官网首页点击“算力市场”菜单。 挑选GPU&#x…

智慧金融合集:财税资金数据管理一体化大屏

随着科技的快速进步和数字化转型的加速&#xff0c;金融、税务等机构和企业面临的数据量呈现出爆炸式增长。传统的数据分析方法早已无法胜任现代业务的需求。为此&#xff0c;许多机构开始尝试创新的软件工具来更好的管理繁琐的数据。 通过图扑软件的数据可视化大屏&#xff0c…

基于springboot社区医疗后台管理系统

基于Spring Boot的社区医疗后台管理系统是一种专为社区医疗机构设计的管理工具&#xff0c;旨在提高医疗服务的质量和效率。 一、系统背景与目的 社区医疗作为基层医疗服务的重要组成部分&#xff0c;承担着为社区居民提供基本医疗服务和公共卫生服务的重任。然而&#xff0c…

基于quartz,刷新定时器的cron表达式

文章目录 前言基于quartz&#xff0c;刷新定时器的cron表达式1. 先看一下测试效果2. 实现代码 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&…

63,【3】buuctf web Upload-Labs-Linux 1

进入靶场 点击pass1 查看提示 既然是上传文件&#xff0c;先构造一句话木马&#xff0c;便于用蚁剑连接 <?php eval($_POST[123])?> 上传木马 文件后缀写为.php.jpg 右键复制图片地址 打开蚁剑连接 先点击测试连接&#xff0c;显示成功后&#xff0c;再点击添加即可 …

Linux操作命令之云计算基础命令

一、图形化界面/文本模式 ctrlaltF2-6 图形切换到文本 ctrlalt 鼠标跳出虚拟机 ctrlaltF1 文本切换到图形 shift ctrl "" 扩大 ctrl "-" 缩小 shift ctrl "n" 新终端 shift ctrl "t" 新标签 alt 1,…

计算机毕业设计hadoop+spark视频推荐系统 短视频推荐系统 视频流量预测系统 短视频爬虫 视频数据分析 视频可视化 视频大数据 大数据

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

【智能解析多线程:线程安全与死锁的深度剖析】

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 温故而知新线程安全问题多线程中有的线程未加锁一个线程有多把锁加了多层锁的代码&#xff0c;执行…

Grafana系列之面板接入Prometheus Alertmanager

关于Grafana的仪表板Dashboard&#xff0c;以及面板Panel&#xff0c;参考Grafana系列之Dashboard。可以直接在面板上创建Alert&#xff0c;即所谓的Grafana Alert&#xff0c;参考Grafana系列之Grafana Alert。除了Grafana Alert外&#xff0c;面板也可接入Prometheus Alertma…

【深度学习入门】深度学习知识点总结

一、卷积 &#xff08;1&#xff09;什么是卷积 定义&#xff1a;特征图的局部与卷积核做内积的操作。 作用&#xff1a;① 广泛应用于图像处理领域。卷积操作可以提取图片中的特征&#xff0c;低层的卷积层提取局部特征&#xff0c;如&#xff1a;边缘、线条、角。 ② 高层…

数据结构 链表2

目录 前言&#xff1a; 一&#xff0c;反转一个链表(迭代) 二&#xff0c;打印一个链表&#xff08;递归&#xff09; 三&#xff0c;反转一个链表(递归) 四&#xff0c;双向链表 总结 前言&#xff1a; 我们根据 [文章 链表1] 可以知道链表相比较于数组的优缺点和计算机…

curl简介与libcurl开源库的使用总结

curl工具和libcurl不是同一个东西&#xff0c;二者的关系主要体现在以下方面&#xff1a; 定义与性质 curl工具&#xff1a; 是一个利用URL语法在命令行下工作的文件传输工具&#xff0c;1997年首次发行。它支持多种协议&#xff0c;如HTTP、HTTPS、FTP、FTPS等&#xff0c;可用…

node.js 07.npm下包慢的问题与nrm的使用

一.npm下包慢 因为npm i 默认从npm官网服务器进行下包,但是npm官网服务器是海外服务器所以响应很慢. 于是我们通过npm下包的时候通常用淘宝镜像进行下包,下面是切换到淘宝镜像地址下包的操作. 二.nrm的使用 nrm是一个管理切换npm下包地址的工具,可以快速切换下包的地址. 安…

Flutter:carousel_slider 横向轮播图、垂直轮播公告栏实现

安装依赖 carousel_slider: ^5.0.01、垂直滚动公告栏 import package:carousel_slider/carousel_options.dart;// 垂直滚动公告栏Widget _buildNotice() {return <Widget>[<Widget>[TDImage(assetUrl: "assets/img/home11.png",width: 60.w,height: 60.w…

RavenMarket:用AI和区块链重塑预测市场

不论是美股市场还是加密市场&#xff0c;AI都是本轮周期里的最大叙事。本轮AI的最大受益者英伟达市值超越苹果一跃成为全球第一大公司&#xff0c;加密领域围绕着AI的创新也是层出不穷&#xff0c;很多项目方开始向着AI转型。 而近期币圈最热门的板块就是AI agent&#xff0c;…

【玩转全栈】----Django基本配置和介绍

目录 Django基本介绍&#xff1a; Django基本配置&#xff1a; 安装Django 创建项目 创建app 注册app Django配置路由URL Django创建视图 启动项目 Django基本介绍&#xff1a; Django是一个开源的、基于Python的高级Web框架&#xff0c;旨在以快速、简洁的方式构建高质量的Web…