分类

类型:
不限 游戏开发 计算机程序开发 Android开发 网站开发 笔记总结 其他
评分:
不限 10 9 8 7 6 5 4 3 2 1
原创:
不限
年份:
不限 2018 2019 2020 2021

技术文章列表

  • mysql 与 oralce 的区别

    一、宏观上
    Oracle是大型的数据库而Mysql是中小型数据库;Mysql是开源的,Oracle是收费的,且价格昂贵
    Oracle支持大并发,大访问量,是OLTP的最好的工具
    安装占用的内存也是有差别,Mysql安装完成之后占用的内存远远小于Oracle所占用的内存,并且Oracle越用所占内存也会变多

    二、微观上
    对于事务的支持

    Mysql对于事务默认是不支持的,只是有某些存储引擎中如:innodb可以支持;而Oracle对于事物是完全支持的
    并发性

    什么是并发性?并发性是OLTP(On-Line Transaction Processing联机事务处理过程)数据库最重要的特性,并发性涉及到资源的获取、共享与锁定Mysql以表锁为主,对资源锁定的力度很大,如果一个session对一个表加锁时间过长,会让其他session无法更新此表的数据Oracle使用行级锁,对资源锁定的力度要小很多,只是锁定sql需要的资源,并且加锁是在数据库中的数据行上,不依赖于索引。所以oracle对并发性的支持要好很多
    数据的持久性

    Oracle保证提交的事务均可以恢复,因为Oracle把提交的sql操作线写入了在线联机日志文件中,保存到磁盘上,如果出现数据库或者主机异常重启,重启Oracle可以靠联机在线日志恢复客户提交的数据Mysql默认提交sql语句,但是如果更新过程中出现db或者主机重启的问题,也可能会丢失数据
    事务隔离级别

    MySQL是repeatable read的隔离级别,而Oracle是read commited的隔离级别,同时二者都支持serializable串行化事务隔离级别,可以实现最高级别的读一致性。每个session提交后其他session才能看到提交的更改。Oracle通过在undo表空间中构造多版本数据块来实现读一致性,每个session 查询时,如果对应的数据块发生变化,Oracle会在undo表空间中为这个session构造它查询时的旧的数据块MySQL没有类似Oracle的构造多版本数据块的机制,只支持read commited的隔离级别。一个session读取数据时,其他session不能更改数据,但可以在表最后插入数据。session更新数据时,要加上排它锁,其他session无法访问数据
    提交方式

    Oracle默认不自动提交,需要手动提交。Mysql默认自动提交
    逻辑备份

    Mysql逻辑备份是要锁定数据,才能保证备份的数据是一致的,影响业务正常的DML(数据操纵语言Data Manipulation Language)使用;Oracle逻辑备份时不锁定数据,且备份的数据是一致的
    sql语句的灵活性

    mysql对sql语句有很多非常实用而方便的扩展,比如limit功能(分页),insert可以一次插入多行数据;Oracle在这方面感觉更加稳重传统一些,Oracle的分页是通过伪列和子查询完成的,插入数据只能一行行的插入数据
    数据复制

    MySQL:复制服务器配置简单,但主库出问题时,丛库有可能丢失一定的数据。且需要手工切换丛库到主库Oracle:既有推或拉式的传统数据复制,也有dataguard的双机或多机容灾机制,主库出现问题是,可以自动切换备库到主库,但配置管理较复杂
    分区表和分区索引

    MySQL的分区表还不太成熟稳定;Oracle的分区表和分区索引功能很成熟,可以提高用户访问db的体验
    售后与费用

    Oracle是收费的,出问题找客服;Mysql是免费的的,开源的,出问题自己解决
    权限与安全

    Oracle的权限与安全概念比较传统,中规中矩;MySQL的用户与主机有关,感觉没有什么意义,另外更容易被仿冒主机及ip有可乘之机
    性能诊断方面

    Oracle有各种成熟的性能诊断调优工具,能实现很多自动分析、诊断功能。比如awr、addm、sqltrace、tkproof等 ;MySQL的诊断调优方法较少,主要有慢查询日志
    0 留言 2021-04-20 08:39:06 奖励24点积分
  • WINAPI和MFC窗口建立区别

    一、基本概念
    SDK JDK IDE
    API
    WINAPI:windows平台下的系统调用,windows.h,调用系统提供的特殊接口,得到系统的资源
    窗口:父窗口和子窗口,客户区和非客户区
    句柄:结构体变量,窗口句柄HWND,图标句柄HICO
    消息队列
    消息
    窗口过程函数
    main()
    WinMain() //WINAPI 人口地址

    二、WinAPI窗口程序
    定义人口函数WinMain()
    创建一个窗口

    设计窗口类WNDCLASS(给成员变量赋值)注册窗口类,告诉系统窗口过程函数的人口地址创建窗口类显示和更新窗口
    消息循环
    窗口过程函数

    MSDN: WinApi,MFC中文参考文档
    三、MFC窗口程序
    应用程序类:CWinApp
    框架类:CFrameWnd

    应用程序类CWinApp, 它的派生类(子类)
    class MyApp: public CWinApp{public: //MFC程序的入口地址 virtual BOOL InitInstance(); //程序的人口地址private:};
    框架类CFrameWnd, 它的派生类(子类)
    class MyFrame : public CFrameWnd{public: MyFrame();//构造函数中创建窗口Create()private:};

    有一个全局的应用程序类对象,编译时自动调用 MyApp myApp;
    在应用程序类 MyApp 的入口函数 InitInstance() 中实现功能

    创建框架类对象并且动态分配空间(自动调用它的构造函数)
    在框架类MyFrame构造函数里创建窗口:CWnd::Create
    框架类对象显示窗口:CWnd::ShowWindow框架类对象更新窗口:CWnd::UpdateWindow保存框架类对象指针:CWinThread::m_pMainWnd // 程序自动声明的
    CWinThread(窗口线程类)


    消息映射

    在操作类中声明消息映射宏和消息处理函数,在 .h 中声明
    DECLARE_MESSAGE_MAP() //宏声明afx_msg void OnLButtonDown( UINT, CPoint );
    在 .cpp 中定义消息宏和实现消息函数
    BEGIN_MESSAGE_MAP(MyFrame,CFrameWnd) ON_WM_LBUTTONDOWN()END_MESSAGE_MAP()
    void MyFrame::OnLButtonDown(UINT, CPoint){ MessageBox( _T("鼠标左键点击") );}

    四、根据向导创建工程
    文档视图结构

    文档类存储数据视图显示和修改数据框架类,类似容器,里面装了视图类
    几个比较重要的函数

    应用程序类 CWinApp 中的 InitInstance() // 程序人口函数
    框架类 CFrameWnd 中的 PreCreateWindow() // 窗口之前调用 OnCreate() // 窗口之后调用
    视图类 CView 中的 OnDraw() //绘图

    WM_PAINT的消息处理函数OnPaint()内部调用OnDraw()OnPaint()和OnDraw()同时存在,OnDraw()无效i

    框架类和视图类区别:框架中存放视图,视图相当于壁纸

    五、字符集
    ANSI:多字节、单字节
    char p[]="abcde"; //一个字符一个字节
    unicode:宽字节、2个字节

    包括 TCHAR
    MFC:TCHAR 自适应字节(按条件编译)

    这两个一样:
    TEXT("")_T("")
    六、拓展
    afx_xxxx: 全局函数,不属于某个类独有
    xxxEx、xxxW:拓展
    MFC命名风格:

    类名和函数名:单词首字母大写,例如class MyClass(){};void SetName(){}
    形参:首字母小写,例如 isPoint
    成员变量加 m_,例如m_xxxxxm_hWnd

    2 留言 2021-04-19 08:53:55 奖励30点积分
  • 结巴分词的简单介绍

    简要说明
    结巴分词支持三种分词模式,支持繁体字,支持自定义词典。
    三种分词模式:

    全模式:把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义
    精简模式:把句子最精确的分开,不会添加多余单词,看起来就像是把句子分割一下
    搜索引擎模式:在精简模式下,对长词再度切分

    # -*- encoding=utf-8 -*-import jiebaif __name__ == '__main__': str1 = '我去北京天安门广场跳舞' a = jieba.lcut(str1, cut_all=True) # 全模式 print('全模式:{}'.format(a)) b = jieba.lcut(str1, cut_all=False) # 精简模式 print('精简模式:{}'.format(b)) c = jieba.lcut_for_search(str1) # 搜索引擎模式 print('搜索引擎模式:{}'.format(c))
    1 留言 2021-04-15 08:51:22 奖励10点积分
  • 上传资源,获取积分 精华

    上传资源,获取积分“WRITE-BUG技术共享平台”是一个专注于校园计算机技术交流共享的平台,面向的主要目标群体是我们计算机相关专业的大学生。在平台上,大家既可以交流学校课内学习的心得体会,也可以分享自己课外积累的技术经验。
    为了充实平台的资源库,更好地服务于各位同学,平台决定推出“众源计划”,有偿征集同学们自己计算机专业的作业、课程设计或是毕业设计等资源。“众源计划”的主要目的是创建一个具有一定规模的“技术资源库”,资源库里的每一份资源,都必须有详细的开发文档和可编译的源代码。
    作业、课程设计或是毕业设计等资源是同学们自己辛苦付出的成果,也是自己技术进步的见证。这部分资源通常都有详细的开发文档和完整的程序源代码,能够帮助其他初学者更好地消化和吸收将要学习的技术,降低学习门槛。所以,平台决定积分奖励征集这些资源。
    具体要求奖励方式
    资源上传并审核通过后,根据资源质量,奖励每贴 10 - 100 点积分
    上传流程
    会员登录自己的账号上传资源
    资源上传后,管理员会在 24 小时之内审核资源
    审核通过后,管理员会立即发放奖励积分至所对应账户

    审核重点
    重点审核资源是否具有详细的文档和完整的源代码
    审查资源是否原创,切勿重复提交

    资源要求“众源计划”仅对两类资源进行积分奖励征集,分别是“课内资源”和“课外资源”,各类资源具体要求如下所示。

    课内资源

    内容范围:计算机相关专业课内的毕业设计、课程设计、小学期、大作业等课程内开发的程序,程序包括游戏、PC程序、APP、网站或者其他软件形式
    内容要求:资源必须要包括完整的程序源代码和详细的开发文档或报告

    课外资源

    内容范围:计算机相关专业的课外自己主导研究游戏、项目、竞赛、个人研究等,区别于课程设计和毕业设计等课内资源
    内容要求:资源必须要包括完整的程序源代码和详细的开发文档或报告


    使用须知** 在上传资源前,请花两分钟阅读 “使用须知” 部分内容 **
    44 留言 2019-01-24 09:26:15 奖励100点积分
  • 传值赋值和引用赋值

    传值赋值$a = 3;$b = 5;
    如果是新手的话,可能会对这个 = 号产生误会,这个等号就是赋值用的。
    $a = $b;
    发生了什么?把 $b 的值读出来,再把值放到 $a 的空间里,即赋值给 $a。
    就是把 $b 的值,传递给 $a,因此叫传值赋值。
    echo $a; // $a=5
    在这个过程中,仅仅参考了一个 $b 的值;然后,把 $b 的值,复制一份到 $a 的空间里去了。
    之后,$a、$b 两者之间还是没有关系,因为 $a、$b 的值还是放在了各自的空间里。
    引用赋值$a = 3;$b = 5;
    下面这行代码,把 $a 这把钥匙的指向,指向了 $b 的地址,即 $a、$b 指向同一个地址;就像,两把钥匙指向了同一个房间。
    $a = &$b;echo $a,$b; // $a=5, $b=5$b = 9;echo $a,$b; // $a=9, $b=9
    看看下面的问题
    unset($b);echo $a; // $a=9
    原因很简单,因为 $a、$b 两个变量指向了同一地址,$b 销毁了,$a 没有销毁。变量有一个机制,当某段地址存的值,有一个变量在指向他的时候,就不会被回收。(这也是简单的回收机制)
    张三 ===> [饭桌] <=== 李四
    张三转一下桌子,在李四看来,桌子的盘子也变了, $a、$b 值,一改全改。
    unset($b);
    张三人走了,但是李四还没有走,服务员会去清理桌子吗?
    答案:不会的!因为还有李四坐在桌子前。如果李四走了,也给unset()掉,那么桌子上的饭菜才能真正的清掉。
    0 留言 2021-04-17 10:37:26 奖励20点积分
  • 基于PsSetCreateProcessNotifyRoutineEx实现监控进程创建并阻止创建

    背景对于内核层实现监控进程的创建或者退出,你可能第一时间会想到 HOOK 内核函数 ZwOpenProcess、ZwTerminateProcess 等。确定,在内核层中的 HOOK 已经给人留下太多深刻的印象了,有 SSDT HOOK、Inline HOOK、IRP HOOK、过滤驱动等等。
    但是,Windows 其实给我们提供现成的内核函数接口,方便我们在内核下监控用户层上进程的创建和退出的情况。即 PsSetCreateProcessNotifyRoutineEx 内核函数,可以设置一个回调函数,来监控进程的创建和退出,同时还能控制是否允许创建进程。
    现在,本文就使用 PsSetCreateProcessNotifyRoutineEx 实现监控进程的创建的实现过程和原理进行整理,形成文档,分享给大家。
    函数介绍PsSetCreateProcessNotifyRoutineEx 函数
    设置进程回调监控进程创建与退出,而且还能控制是否允许进程创建。
    函数声明
    NTSTATUS PsSetCreateProcessNotifyRoutineEx( _In_ PCREATE_PROCESS_NOTIFY_ROUTINE_EX NotifyRoutine, _In_ BOOLEAN Remove);
    参数

    NotifyRoutine [in]指向PCREATE_PROCESS_NOTIFY_ROUTINE_EX例程以注册或删除的指针。 创建新进程时,操作系统将调用此例程。Remove[in]一个布尔值,指定PsSetCreateProcessNotifyRoutineEx是否会从回调例程列表中添加或删除指定的例程。 如果此参数为TRUE,则从回调例程列表中删除指定的例程。 如果此参数为FALSE,则将指定的例程添加到回调例程列表中。 如果删除为TRUE,系统还会等待所有正在运行的回调例程运行完成。
    返回值

    成功,则返回 STATUS_SUCCESS;否则,返回其它失败错误码 NTSTATUS。

    PCREATE_PROCESS_NOTIFY_ROUTINE_EX 回调函数
    函数声明
    PCREATE_PROCESS_NOTIFY_ROUTINE_EX SetCreateProcessNotifyRoutineEx;void SetCreateProcessNotifyRoutineEx( _In_ HANDLE ParentId, _In_ HANDLE ProcessId, _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo){ ... }
    参数

    ParentId [in]父进程的进程ID。ProcessId [in]进程的进程ID。CreateInfo [in,out,optional]指向PS_CREATE_NOTIFY_INFO结构的指针,其中包含有关新进程的信息。为 NULL 时,表示进程退出;不为 NULL 时,表示进程创建。
    返回值

    无返回值。

    PS_CREATE_NOTIFY_INFO 结构体
    typedef struct _PS_CREATE_NOTIFY_INFO { SIZE_T Size; union { ULONG Flags; struct { ULONG FileOpenNameAvailable :1; ULONG IsSubsystemProcess :1; ULONG Reserved :30; }; }; HANDLE ParentProcessId; CLIENT_ID CreatingThreadId; struct _FILE_OBJECT *FileObject; PCUNICODE_STRING ImageFileName; PCUNICODE_STRING CommandLine; NTSTATUS CreationStatus;} PS_CREATE_NOTIFY_INFO, *PPS_CREATE_NOTIFY_INFO;
    成员

    Size该结构的大小(以字节为单位)。 Flags保留。 请改用FileOpenNameAvailable成员。FileOpenNameAvailable一个布尔值,指定ImageFileName成员是否包含用于打开进程可执行文件的确切文件名。
    IsSubsystemProcess指示进程子系统类型的布尔值是Win32以外的子系统。
    Reserved保留供系统使用。
    ParentProcessId新进程的父进程的进程ID。 请注意,父进程不一定与创建新进程的进程相同。 新进程可以继承父进程的某些属性,如句柄或共享内存。 (进程创建者的进程ID由CreatingThreadId-> UniqueProcess给出。)
    CreatingThreadId创建新进程的进程和线程的进程ID和线程ID。 CreatingThreadId-> UniqueProcess包含进程ID,而CreatingThreadId-> UniqueThread包含线程ID。
    FileObject指向进程可执行文件的文件对象的指针。如果IsSubsystemProcess为TRUE,则此值可能为NULL。
    ImageFileName指向保存可执行文件的文件名的UNICODE_STRING字符串的指针。 如果FileOpenNameAvailable成员为TRUE,则该字符串指定用于打开可执行文件的确切文件名。 如果FileOpenNameAvailable为FALSE,则操作系统可能仅提供部分名称。如果IsSubsystemProcess为TRUE,则此值可能为NULL。
    CommandLine指向UNICODE_STRING字符串的指针,该字符串保存用于执行该过程的命令。 如果命令不可用,CommandLine为NULL。如果IsSubsystemProcess为TRUE,则此值可能为NULL。
    CreationStatus用于进程创建操作返回的NTSTATUS值。 驱动程序可以将此值更改为错误代码,以防止创建进程。


    实现原理破解 PsSetCreateProcessNotifyRoutineEx 函数的使用限制第一种方法在讲解怎么使用 PsSetCreateProcessNotifyRoutineEx 函数来注册回调之前,先来讲解下 Windows 对这个函数做的限制:驱动程序必须有数字签名才能使用此函数。经逆向研究,内核通过 MmVerifyCallbackFunction 验证此回调是否合法, 但此函数只是简单的验证了一下 DriverObject->DriverSection->Flags 的值是不是为 0x20:
    nt!MmVerifyCallbackFunction+0x75: fffff800`01a66865 f6406820 test byte ptr [rax+68h],20h fffff800`01a66869 0f45fd cmovne edi,ebp
    所以破解方法非常简单,只要把 DriverObject->DriverSection->Flags 的值按位或 0x20 即可。其中,DriverSection 是指向 LDR_DATA_TABLE_ENTRY 结构的值,要注意该结构在 32 位和 64 位系统下的定义。
    // 注意32位与64位的对齐大小#ifndef _WIN64 #pragma pack(1) #endiftypedef struct _LDR_DATA_TABLE_ENTRY{ LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; union { LIST_ENTRY HashLinks; struct { PVOID SectionPointer; ULONG CheckSum; }; }; union { ULONG TimeDateStamp; PVOID LoadedImports; }; PVOID EntryPointActivationContext; PVOID PatchInformation; LIST_ENTRY ForwarderLinks; LIST_ENTRY ServiceTagLinks; LIST_ENTRY StaticLinks;} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;#ifndef _WIN64 #pragma pack()#endif
    第二种方法使用此函数, 一定要设置 IMAGE_OPTIONAL_HEADER 中的 DllCharacterisitics 字段设置为:IMAGE_DLLCHARACTERISITICS_FORCE_INTEGRITY 属性,该属性是一个驱动强制签名属性。使用 VS2013 开发环境设置方式是:

    右击项目,选择属性
    选中配置属性中的链接器,点击命令行
    在其它选项中输入: /INTEGRITYCHECK 表示设置; /INTEGRITYCHECK:NO 表示不设置

    这样,设置之后,驱动程序必须要进行驱动签名才可正常运行!
    创建回调并监控进程创建我们根据上面的函数介绍,大概知道实现的流程了吧。对于设置回调函数,直接调用 PsSetCreateProcessNotifyRoutineEx 函数来设置就好。传入设置的回调函数名称以及删除标志参数设置为 FALSE,表示创建回调函数。这样,就可以成功设置进程监控的回调函数了。
    那么,我们的回调函数也并不复杂,它的函数声明为:
    void SetCreateProcessNotifyRoutineEx( _In_ HANDLE ParentId, _In_ HANDLE ProcessId, _Inout_opt_ PPS_CREATE_NOTIFY_INFO CreateInfo);
    回调函数的名称可以任意,但是返回值类型以及函数参数类型必须是固定的,不能变更。回调函数的第一个参数 ParentId 表示父进程ID,第二个参数 ProcessId 表示进程ID,第三个参数 CreateInfo 为 NULL 时,表示进程退出;不为 NULL 时,表示进程创建。那么,创建进程的信息就存储在 PS_CREATE_NOTIFY_INFO 结构体中。
    我们可以从 PS_CREATE_NOTIFY_INFO 中获取进程名称、路径、命令行、PID等进程信息。同时,可以通过设置成员 CreationStatus 的值来控制进程是否创建。当 CreationStatus 的值为 STATUS_SUCCESS 表示创建进程,否则,不创建进程。例如不创建进程的时候,CreationStatus 可以为 STATUS_UNSUCCESSFUL 错误码。
    当我们要删除回调设置的时候,只需要调用 PsSetCreateProcessNotifyRoutineEx 函数,传入回调函数名称以及删除标志参数设置为 TRUE。这样,就可以成功删除设置的回调函数了。
    编码实现编程方式绕过签名检查// 编程方式绕过签名检查BOOLEAN BypassCheckSign(PDRIVER_OBJECT pDriverObject){#ifdef _WIN64 typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY listEntry; ULONG64 __Undefined1; ULONG64 __Undefined2; ULONG64 __Undefined3; ULONG64 NonPagedDebugInfo; ULONG64 DllBase; ULONG64 EntryPoint; ULONG SizeOfImage; UNICODE_STRING path; UNICODE_STRING name; ULONG Flags; USHORT LoadCount; USHORT __Undefined5; ULONG64 __Undefined6; ULONG CheckSum; ULONG __padding1; ULONG TimeDateStamp; ULONG __padding2; } KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;#else typedef struct _KLDR_DATA_TABLE_ENTRY { LIST_ENTRY listEntry; ULONG unknown1; ULONG unknown2; ULONG unknown3; ULONG unknown4; ULONG unknown5; ULONG unknown6; ULONG unknown7; UNICODE_STRING path; UNICODE_STRING name; ULONG Flags; } KLDR_DATA_TABLE_ENTRY, *PKLDR_DATA_TABLE_ENTRY;#endif PKLDR_DATA_TABLE_ENTRY pLdrData = (PKLDR_DATA_TABLE_ENTRY)pDriverObject->DriverSection; pLdrData->Flags = pLdrData->Flags | 0x20; return TRUE;}
    设置回调// 设置回调函数NTSTATUS SetProcessNotifyRoutine(){ NTSTATUS status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)ProcessNotifyExRoutine, FALSE); if (!NT_SUCCESS(status)) { ShowError("PsSetCreateProcessNotifyRoutineEx", status); } return status;}
    回调函数// 回调函数VOID ProcessNotifyExRoutine(PEPROCESS pEProcess, HANDLE hProcessId, PPS_CREATE_NOTIFY_INFO CreateInfo){ // CreateInfo 为 NULL 时,表示进程退出;不为 NULL 时,表示进程创建 if (NULL == CreateInfo) { return; } // 获取进程名称 PCHAR pszImageFileName = PsGetProcessImageFileName(pEProcess); // 显示创建进程信息 DbgPrint("[%s][%d][%wZ]\n", pszImageFileName, hProcessId, CreateInfo->ImageFileName); // 禁止指定进程(520.exe)创建 if (0 == _stricmp(pszImageFileName, "520.exe")) { // 禁止创建 CreateInfo->CreationStatus = STATUS_UNSUCCESSFUL; DbgPrint("[禁止创建]\n"); }}
    删除回调// 删除回调函数NTSTATUS RemoveProcessNotifyRoutine(){ NTSTATUS status = PsSetCreateProcessNotifyRoutineEx((PCREATE_PROCESS_NOTIFY_ROUTINE_EX)ProcessNotifyExRoutine, TRUE); if (!NT_SUCCESS(status)) { ShowError("PsSetCreateProcessNotifyRoutineEx", status); } return status;}
    程序测试在 Win7 32 位系统下,驱动程序正常执行:

    在 Win10 64 位系统下,驱动程序正常执行:

    总结这个程序实现起来并不复杂,关键是对 PsSetCreateProcessNotifyRoutineEx 函数要理解透彻,理解清楚回调函数中,PS_CREATE_NOTIFY_INFO 结构体的所有成员含义。这样,我们就可以获取进程信息,以及控制进程的创建。
    注意,破解 PsSetCreateProcessNotifyRoutineEx 函数的使用限制有两种方式,一种是通过编程来解决;一种是通过 VS 开发环境和数字签名来解决。
    参考参考自《Windows黑客编程技术详解》一书
    2 留言 2019-02-16 14:37:41 奖励8点积分
  • 基于SSM的超市订单管理系统

    1 系统需求分析超市订单管理系统是一个专为连锁店、超市等商业场所提供订单管理平台的系统。该系统的目标是建立一个订单管理平台,为需要合理规划超市供应链、供应商以及工作人员提供的便捷的平台。该系统的主要业务需求包括记录并维护某超市的供应商信息,以及该超市与供应商之间的交易订单信息,包括三种角色,系统管理员经理,普通员工。
    1.1 系统功能分析本系统主要的功能是实现超市订单管理功能,以便为超市、连锁店提供以及其他负责人提供订单详情、联系方式等,系统的主要功能有以下五个方面:

    登录/注销:管理员可以在网站上登录浏览,离开时注销并退出
    订单管理:管理员可以浏览所有订单信息,并且通过点击查看了解订单详情信息
    供应商管理:管理员可以在网站浏览所有供应商信息,并在在与其他供应商达成合作之后,添加相关供应商信息,并且通过点击查看了解他们的联系方式等
    用户管理:管理员可以管理所有超市员工用户,对用户进行增删改查,对于离职或其他原因的未工作用户给予注销管理
    密码修改:管理员可对自己的账号密码进行修改,填写对应之前的正确密码以及新密码之后,即完成相关修改密码操作
    搜索功能:在以上管理界面中,均允许了管理员根据关键字进行搜索,要求搜索框中输入的字段必须完全包含在物品名称中,否则无法查询


    1.2 系统功能需求根据系统功能要求,该超市订单管理系统以管理员为中心的用户角色,可以将系统分解成几个模块来分别设计应用程序界面,如图 1.1所示。

    1.3 系统性能需求超市订单管理系统的开发是在Window10平台上,以SSM为架构,采用MySQL 作为数据库管理系统管理后台数据库。本系统是超市信息管理建设中必不可少的一部分,它实现了现代管理信息系统的大部分功能需要。使用本系统可以使超市管理更加方便快捷,合理的页面设计也使得这个用户充分享受到基于Internet管理信息系统的优越。本系统开发说明:
    1.3.1 功能完备在开发初期,查看了大量关于电子商务,管理信息系统,J2EE等方面的资料,同时借鉴了很多其他电子商务网站和管理信息的流程。经过总结,确定了满足需求分析的基本模块。系统总体设计上实现了整个系统模块的划分,系统主要包含5大模块,分别是:订单管理信息,供应商管理,用户管理,修改密码,登陆退出系统,基本上实现了综合管理系统的所有功能。 
    1.3.2 界面友好系统用户登陆到管理页面后,每页有导航和引领的作用。系统具有自适应的能力,同时导航条方便快捷的引导用户进行各种合理的操作。
    1.3.3 管理科学本系统一开始就从管理学的角度做出了详细细致的考虑,后来有参考了电子商务管理等,最后才做出了系统总体设计,因此可以讲该系统是较为科学的。
    系统的性能需求主要表现在数据库中的各个表需要频繁地被插入、删除以及更新。对于用户来说,系统地响应时间不宜太长,否则会降低用户体验。为此要求我们建立良好的表结构,加上足够的存储空间以及硬件性能。
    2 可行性分析2.1 研究前提随着我国经济情况的日新月异,飞速发展,涌现出许许多多的超市和便利店。越来越多的人喜欢到超市购物,超市里销售的商品也呈现出多种多样的变化趋势。我们开发一个超市订单管理系统,它可以对仓储各环节实施全过程控制管理,对整个进货、退货、盘点等各个环节的规范化作业,控制整个过程的正常运行。去掉了手工书写票据和送到机房输入的步骤,解决库房信息陈旧滞后的弊病,方便了仓库管理人员对物品的放置和调配,提高了工作效率。
    该系统容易被接受,具有简单易学性,便于管理等功能,是对超市订单管理的一种有效工具。
    2.2 设计要求2.2.1 安全性超市订单管理增强对产品规范的审计,重点确定该项目中需要审计的产品。买家只能针对卖家允许公开的信息进行查阅。买家只享受对自己账号内数据的查阅权,与定后处理权,订货支付权,申请退货权,不允许偷窥其他人。卖家只能针对买家允许公开的信息进行查阅。卖家只享受对自己账号内数据的查阅权,发货权,退款相应处理权,不允许偷窥其他人。
    2.2.2 系统性能管理员登录查看超市供应商与超市员工用户管理,可以进行增、删、改、查等操作。超市订单系统可以使超市的管理趋于正规化、现代化和系统化。本项目的产品可以达到以下目标:

    提高工作效率,减少返工
    业务流程的流水线化
    符合相关标准和规则
    与目前的应用产品相比较,提高了可用性或减少了失效程度

    2.2.3 可扩展性所有信息呈现,操作完全由打开的网页呈现并完成。本系统所占有的是超市市场,它追求的是简单、易学、易用,能够更好地解决管理人员的负担,能够辅助超市有效的管理物品。对于订单管理系统的用户,可满足对订单管理的需求,且此种需求被接受并且满足,其系统便可以推广。

    3 数据库设计3.1 数据库需求分析经过对超市管理系统的调查分析,得出用户的需求大致如下:

    管理员可以在系统中对订单、供应商以及用户进行增、删、改、查的处理
    管理员需要输入账号密码登录,并且可以增添新的管理员

    如下是利用数据流图方法对数据库做需求分析:
    第一步:由用户的需求,可以得到顶层数据流图如图3.1.1所示。

    第二步:超市订单管理系统的第1层数据流图如图3.1.2所示。

    第三步:超市订单管理系统的第2层数据库流图——订单管理的细化数据流图如图3.1.3所示。

    第四步:超市订单管理系统的第2层数据流库——供应商管理的细化数据流图如图3.1.4所示。

    第五步:超市订单管理系统的第2层数据流库——用户管理的细化数据流图如图3.1.5所示。

    根据如上的数据流程图,可以列出以下记录超市订单管理所需的数据项和数据结构:

    管理员:管理员ID、管理员姓名、管理员密码、管理员性别、管理员角色、管理员出生日期、管理员电话、管理员住址
    订单:订单编码、商品名称、供应商名称、订单金额、是否付款
    供应商:供应商编码、供应商名称、联系人、联系电话、微信

    3.2 数据库概念结构设计本系统一共有用户、供应商、订单、角色、地址这五个基本实体。
    管理员可以对应多个订单,而一个订单只能对应于一个管理员。管理员可以管理多个供应商,而一个供应商只能对应于一个管理员。一个供应商可以对应多条订单,但一条订单只能对应于一个供应商。此外,有一个用户对应一个角色,一个角色对应多个用户;一个地址对应多个订单,一个订单对应一个地址。数据库表之间的关系如下:


    用户:主键ID、用户编码、用户名称、用户密码、性别、出生日期、手机、地址、用户角色、创建者、创建时间、更新者、更新时间、用户头像、工作照
    账单:订单编号、订单编码、商品名称、商品描述、商品单位、商品数量、商品总额、是否支付、创建者、创建时间、更新者、更新时间、供应商ID
    供应商:供应商ID、供货商编码、供货商名称、供应商详细描述、供应商联系人、联系电话、地址、微信、创建者、创建时间、更新时间、更新者、营业执照、组织机构代码证
    地址:主键ID、联系人姓名、收货地址明细、邮编、联系人电话、创建者、创建日期、修改者、修改时间、用户ID
    角色:角色编号、角色编码、角色名称、创建者、创建时间、修改者、修改时间

    3.3 数据库逻辑结构设计将概念结构设计中的各个模型转化为DBMS支持的表结构,同时保持不会出现插入异常、删除异常和修改异常,表结构应该做到符合3NF。根据系统 E-R 图,需要设计4个数据表来存放信息。在本系统中,一共有五个实体,实体转化为数据库模型为如下所示:
    一对多联系转化为一个关系模式:

    用户—订单(用户编号,订单编号)
    供货商—订单(供货商编号,订单编号)
    用户—身份(用户编号,身份编号)
    用户—地址(用户编号)

    利用以上关系模式得到的所有数据表如下所示:
    用户表(smbms_user)

    数据项:主键ID、用户编码、用户名称、用户密码、性别、出生日期、手机、地址、用户角色、创建者、创建时间、更新者、更新时间、用户头像、工作照
    说明:用户ID是唯一的用户标识,使此表的主键。如表3.3.1所示。




    列名
    数据类型
    数据长度
    可否为空
    备注




    Id
    bigint
    20
    Not null
    主键ID


    userCode
    varchar
    15
    Not null
    用户编码


    userName
    varchar
    15
    Not null
    用户名称


    userPassword
    varchar
    15
    Not null
    用户密码


    gender
    int
    10

    性别


    birthday
    date


    出生日期


    phone
    varchar
    15

    手机


    address
    varchar
    30

    地址


    userRole
    int
    10

    用户角色


    createdBy
    bigint
    20

    创建者


    creationDate
    datetime


    创建时间


    modifyBy
    bigint
    20

    更新者


    modifyDate
    datetime


    更新时间


    idPicPath
    varchar
    300

    用户头像


    workPicPath
    varchar
    300

    工作照



    供应商表(smbms_provider)

    数据项:供应商ID、供货商编码、供货商名称、供应商详细描述、供应商联系人、联系电话、地址、微信、创建者、创建时间、更新时间、更新者、营业执照、组织机构代码证
    说明:这张表标识的是超市管理信息系统中商品供应商的信息列表,供应商ID是该表的主键
    编号方法:商品供应商ID采用自动生成方式,如表3.3.2所示。




    列名
    数据类型
    数据长度
    可否为空
    备注




    Id
    Bigint
    20
    Not null
    供货商ID(主键)


    proCode
    Varchar
    20
    Not null
    供货商编码


    proName
    varchar
    20
    Not null
    供货商名称


    ProDesc
    varchar
    50

    供应商详细描述


    proContact
    varchar
    20
    Not null
    供货商联系人


    proPhone
    Varchar
    20
    Not null
    联系电话


    ProAddress
    Varchar
    50
    Not null
    供货商地址


    proFax
    varchar
    20

    微信


    CreateBy
    bigint
    20

    创建者


    CreatationDate
    datetime


    创建时间


    modifyDate
    datetime


    更新时间


    modifyBy
    bigint
    20

    更新者


    companyLicPicPath
    varchar
    300

    营业执照


    orgCodePicPath
    varchar
    300

    组织机构代码证



    订单表(smbms_bill)

    数据项:订单编号、订单编码、商品名称、商品描述、商品单位、商品数量、商品总额、是否支付、创建者、创建时间、更新者、更新时间、供应商ID
    说明:这张表标识的是超市管理信息系统订单信息列表,订单ID是该表的主键
    编号方法:订单ID采用自动生成方式,供应商ID与供应商表中供应商ID一一对应,如表3.3.3所示。




    列名
    数据类型
    数据长度
    可否为空
    备注




    Id
    bigint
    20
    Not null
    订单ID(主键)


    billCode
    varchar
    20
    Not null
    订单编码


    ProductName
    Varchar
    20
    Not null
    商品名称


    ProductDescent
    Varchar
    50
    Not null
    商品描述


    ProductUnit
    Varchar
    10
    Not null
    商品单位


    ProductCount
    Decimal
    20,2
    Not null
    商品数量


    totalPrice
    Decimal
    20,2
    Not null
    商品总额


    isPayment
    int
    10
    Not null
    是否支付


    createdBy
    bigint
    20

    创建者


    creationDate
    Datetime


    创建时间


    modifyBy
    bigint
    20

    更新者


    modifyDate
    datetime


    更新时间


    providerID
    Int
    20

    供应商ID



    身份表(smbms_role)

    数据项:角色编号、角色编码、角色名称、创建者、创建时间、修改者、修改时间
    说明:这张表标识的是超市订单管理信息系统中用户身份列表,身份编号是该表的主键
    编号方法:用户身份编号与用户表中的员工身份编号一一对应,如表3.3.4所示。




    列名
    数据类型
    数据长度
    可否为空
    备注




    Id
    bigint
    20
    Not null
    角色ID(主键)


    RoleCode
    varchar
    15
    Not null
    角色编码


    roleName
    Varchar
    15
    Not null
    角色名称


    createdBy
    bigint
    20

    创建者


    creationDate
    datetime


    创建时间


    modifyBy
    bigint
    20

    修改者


    modifyDate
    datetime


    修改时间



    地址表(smbms_address)

    数据项:主键ID、联系人姓名、收货地址明细、邮编、联系人电话、创建者、创建日期、修改者、修改时间、用户ID
    编号方法:用户ID与用户表中的用户ID一一对应,如表3.3.5所示。




    列名
    数据类型
    数据长度
    可否为空
    备注




    Id
    bigint
    20
    Not null
    主键ID(主键)


    Contact
    varchar
    15
    Not null
    联系人姓名


    addressDesce
    Varchar
    50
    Not null
    收货地址明细


    postcode
    Varchar
    15

    邮编


    Tel
    Varchar
    20
    Not null
    联系人电话


    createdBy
    bigint
    20

    创建者


    creationDate
    Datetime


    创建时间


    modifyBy
    bigint
    20

    修改者


    modifyDate
    datetime


    修改时间


    userID
    Bigint
    20

    用户ID



    数据库连接利用了SSM框架的底层的MyBatis,建立了实体类与MySQL之间映射关系,从而实现数据持久化、封装数据库连接等操作。
    3.4 数据库物理结构设计3.4.1 选择关系模式的存取方式对数据库逻辑结构设计中建立的表结构,供应商表的供应商编号属性唯一决定每一个供应商元组,所以对供应商表建立以供应商编号为主关键字的索引。同理,对管理员关系模式、订单关系模式也采用类似的索引存取方法。
    3.4.2 数据表存储结构设计本系统的所有数据表均存放在物理磁盘中。用户表、供应商表和订单表的结构是相对稳定的,表中的已有记录是要长期保存的,在此基础上系统会相应用户的操作对数据表进行增、删、改、查等操作。

    3.5 数据库的建立3.5.1 数据库的建立创建数据库
    create database smbms;USE smbms;
    创建表smbms_address
    DROP TABLE IF EXISTS `smbms_address`;CREATE TABLE `smbms_address` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `contact` varchar(15) COLLATE utf8_unicode_ci NOT NULL COMMENT '联系人姓名', `addressDesc` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT '收货地址明细', `postCode` varchar(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '邮编', `tel` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT '联系人电话', `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者', `creationDate` datetime DEFAULT NULL COMMENT '创建时间', `modifyBy` bigint(20) DEFAULT NULL COMMENT '修改者', `modifyDate` datetime DEFAULT NULL COMMENT '修改时间', `userId` bigint(20) DEFAULT NULL COMMENT '用户ID', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    创建表smbms_bill
    DROP TABLE IF EXISTS `smbms_bill`;CREATE TABLE `smbms_bill` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `billCode` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT '账单编码', `productName` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT '商品名称', `productDesc` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品描述', `productUnit` varchar(10) COLLATE utf8_unicode_ci NOT NULL COMMENT '商品单位', `productCount` decimal(20,2) NOT NULL COMMENT '商品数量', `totalPrice` decimal(20,2) NOT NULL COMMENT '商品总额', `isPayment` int(10) NOT NULL COMMENT '是否支付(1:未支付 2:已支付)', `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者(userId)', `creationDate` datetime DEFAULT NULL COMMENT '创建时间', `modifyBy` bigint(20) DEFAULT NULL COMMENT '更新者(userId)', `modifyDate` datetime DEFAULT NULL COMMENT '更新时间', `providerId` int(20) DEFAULT NULL COMMENT '供应商ID', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    创建表smbms_provider
    DROP TABLE IF EXISTS `smbms_provider`;CREATE TABLE `smbms_provider` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `proCode` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT '供应商编码', `proName` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT '供应商名称', `proDesc` varchar(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商详细描述', `proContact` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT '供应商联系人', `proPhone` varchar(20) COLLATE utf8_unicode_ci NOT NULL COMMENT '联系电话', `proAddress` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT '地址', `proFax` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '微信', `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者(userId)', `creationDate` datetime DEFAULT NULL COMMENT '创建时间', `modifyDate` datetime DEFAULT NULL COMMENT '更新时间', `modifyBy` bigint(20) DEFAULT NULL COMMENT '更新者(userId)', `companyLicPicPath` varchar(300) DEFAULT NULL COMMENT '营业执照', `orgCodePicPath` varchar(300) DEFAULT NULL COMMENT '组织机构代码证', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    创建表smbms_role
    DROP TABLE IF EXISTS `smbms_role`;CREATE TABLE `smbms_role` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `roleCode` varchar(15) COLLATE utf8_unicode_ci NOT NULL COMMENT '角色编码', `roleName` varchar(15) COLLATE utf8_unicode_ci NOT NULL COMMENT '角色名称', `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者', `creationDate` datetime DEFAULT NULL COMMENT '创建时间', `modifyBy` bigint(20) DEFAULT NULL COMMENT '修改者', `modifyDate` datetime DEFAULT NULL COMMENT '修改时间', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    创建表smbms_user
    DROP TABLE IF EXISTS `smbms_user`;CREATE TABLE `smbms_user` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID', `userCode` varchar(15) COLLATE utf8_unicode_ci NOT NULL COMMENT '用户编码', `userName` varchar(15) COLLATE utf8_unicode_ci NOT NULL COMMENT '用户名称', `userPassword` varchar(15) COLLATE utf8_unicode_ci NOT NULL COMMENT '用户密码', `gender` int(10) DEFAULT 2 COMMENT '性别(1:女、 2:男)', `birthday` date DEFAULT NULL COMMENT '出生日期', `phone` varchar(15) COLLATE utf8_unicode_ci NOT NULL COMMENT '手机', `address` varchar(30) COLLATE utf8_unicode_ci NOT NULL COMMENT '地址', `userRole` int(10) DEFAULT NULL COMMENT '用户角色(取自角色表-角色id)', `createdBy` bigint(20) DEFAULT NULL COMMENT '创建者(userId)', `creationDate` datetime DEFAULT NULL COMMENT '创建时间', `modifyBy` bigint(20) DEFAULT NULL COMMENT '更新者(userId)', `modifyDate` datetime DEFAULT NULL COMMENT '更新时间', `idPicPath` varchar(300) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '用户头像', `workPicPath` varchar(300) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '工作照', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
    3.5.2 初始数据的输入数据表创建成功后,数据库中还没有实际的数据。为了保证外部键能使用,数据需要提前输入,如用户编码、用户姓名、订单名称和供应商等等。具体插入语句如下:
    向smbms_address表插入数据
    insert into `smbms_address`(`id`,`contact`,`addressDesc`,`postCode`,`tel`,`createdBy`,`creationDate`,`modifyBy`,`modifyDate`,`userId`) values (1,'王丽','北京市东城区东交民巷44号','100010','13678789999',1,'2020-04-13 00:00:00',NULL,NULL,1),(2,'张红丽','北京市海淀区丹棱街3号','100000','18567672312',1,'2020-04-13 00:00:00',NULL,NULL,1),(3,'任志强','北京市东城区美术馆后街23号','100021','13387906742',1,'2020-04-13 00:00:00',NULL,NULL,1),(4,'曹颖','北京市朝阳区朝阳门南大街14号','100053','13568902323',1,'2020-04-13 00:00:00',NULL,NULL,2),(5,'李慧','北京市西城区三里河路南三巷3号','100032','18032356666',1,'2020-04-13 00:00:00',NULL,NULL,3),(6,'王国强','北京市顺义区高丽营镇金马工业区18号','100061','13787882222',1,'2020-04-13 00:00:00',NULL,NULL,3);
    向smbms_bill表插入数据
    insert into `smbms_bill`(`id`,`billCode`,`productName`,`productDesc`,`productUnit`,`productCount`,`totalPrice`,`isPayment`,`createdBy`,`creationDate`,`modifyBy`,`modifyDate`,`providerId`) values (1,'BILL2016_001','洗发水、护发素','日用品-洗发、护发','瓶','500.00','25000.00',2,1,'2020-06-14 13:02:03',NULL,NULL,13),(2,'BILL2016_002','香皂、肥皂、药皂','日用品-皂类','块','1000.00','10000.00',2,1,'2020-03-23 04:20:40',NULL,NULL,13),(3,'BILL2016_003','大豆油','食品-食用油','斤','300.00','5890.00',2,1,'2020-05-14 13:02:03',NULL,NULL,6),(4,'BILL2016_004','橄榄油','食品-进口食用油','斤','200.00','9800.00',2,1,'2020-04-10 03:12:13',NULL,NULL,7),(5,'BILL2016_005','洗洁精','日用品-厨房清洁','瓶','500.00','7000.00',2,1,'2020-05-14 13:02:03',NULL,NULL,9),(6,'BILL2016_006','美国大杏仁','食品-坚果','袋','300.00','5000.00',2,1,'2020-04-14 06:08:09',NULL,NULL,4),(7,'BILL2016_007','沐浴液、精油','日用品-沐浴类','瓶','500.00','23000.00',1,1,'2020-07-01 10:10:22',NULL,NULL,14),(8,'BILL2016_008','不锈钢盘碗','日用品-厨房用具','个','600.00','6000.00',2,1,'2020-04-14 05:12:13',NULL,NULL,14),(9,'BILL2016_009','塑料杯','日用品-杯子','个','350.00','1750.00',2,1,'2020-02-04 11:40:20',NULL,NULL,14),(10,'BILL2016_010','豆瓣酱','食品-调料','瓶','200.00','2000.00',2,1,'2020-01-29 05:07:03',NULL,NULL,8),(11,'BILL2016_011','海之蓝','饮料-国酒','瓶','50.00','10000.00',1,1,'2020-04-14 16:16:00',NULL,NULL,1),(12,'BILL2016_012','芝华士','饮料-洋酒','瓶','20.00','6000.00',1,1,'2020-06-09 17:00:00',NULL,NULL,1),(13,'BILL2016_013','长城红葡萄酒','饮料-红酒','瓶','60.00','800.00',2,1,'2020-04-14 15:23:00',NULL,NULL,1),(14,'BILL2016_014','泰国香米','食品-大米','斤','400.00','5000.00',2,1,'2020-05-09 15:20:00',NULL,NULL,3),(15,'BILL2016_015','东北大米','食品-大米','斤','600.00','4000.00',2,1,'2020-05-14 14:00:00',NULL,NULL,3),(16,'BILL2016_016','可口可乐','饮料','瓶','2000.00','6000.00',2,1,'2020-03-27 13:03:01',NULL,NULL,2),(17,'BILL2016_017','脉动','饮料','瓶','1500.00','4500.00',2,1,'2020-05-10 12:00:00',NULL,NULL,2),(18,'BILL2016_018','哇哈哈','饮料','瓶','2000.00','4000.00',2,1,'2020-06-24 15:12:03',NULL,NULL,2);
    向smbms_provider表插入数据
    insert into `smbms_provider`(`id`,`proCode`,`proName`,`proDesc`,`proContact`,`proPhone`,`proAddress`,`proFax`,`createdBy`,`creationDate`,`modifyDate`,`modifyBy`) values(1,'BJ_GYS001','北京三木堂商贸有限公司','长期合作伙伴,主营产品:茅台、五粮液、郎酒、酒鬼酒、泸州老窖、赖茅酒、法国红酒等','张国强','13566667777','北京市丰台区育芳园北路','010-58858787',1,'2020-03-21 16:52:07',NULL,NULL),(2,'HB_GYS001','石家庄帅益食品贸易有限公司','长期合作伙伴,主营产品:饮料、水饮料、植物蛋白饮料、休闲食品、果汁饮料、功能饮料等','王军','13309094212','河北省石家庄新华区','0311-67738876',1,'2020-04-13 04:20:40',NULL,NULL),(3,'GZ_GYS001','深圳市泰香米业有限公司','初次合作伙伴,主营产品:良记金轮米,龙轮香米等','郑程瀚','13402013312','广东省深圳市福田区深南大道6006华丰大厦','0755-67776212',1,'2020-03-21 16:56:07',NULL,NULL),(4,'GZ_GYS002','深圳市喜来客商贸有限公司','长期合作伙伴,主营产品:坚果炒货.果脯蜜饯.天然花茶.营养豆豆.特色美食.进口食品.海味零食.肉脯肉','林妮','18599897645','广东省深圳市福龙工业区B2栋3楼西','0755-67772341',1,'2020-03-22 16:52:07',NULL,NULL),(5,'JS_GYS001','兴化佳美调味品厂','长期合作伙伴,主营产品:天然香辛料、鸡精、复合调味料','徐国洋','13754444221','江苏省兴化市林湖工业区','0523-21299098',1,'2020-02-22 16:52:07',NULL,NULL),(6,'BJ_GYS002','北京纳福尔食用油有限公司','长期合作伙伴,主营产品:山茶油、大豆油、花生油、橄榄油等','马莺','13422235678','北京市朝阳区珠江帝景1号楼','010-588634233',1,'2020-03-21 17:52:07',NULL,NULL),(7,'BJ_GYS003','北京国粮食用油有限公司','初次合作伙伴,主营产品:花生油、大豆油、小磨油等','王驰','13344441135','北京大兴青云店开发区','010-588134111',1,'2020-04-13 00:00:00',NULL,NULL),(8,'ZJ_GYS001','慈溪市广和绿色食品厂','长期合作伙伴,主营产品:豆瓣酱、黄豆酱、甜面酱,辣椒,大蒜等农产品','薛圣丹','18099953223','浙江省宁波市慈溪周巷小安村','0574-34449090',1,'2020-01-21 06:02:07',NULL,NULL),(9,'GX_GYS001','优百商贸有限公司','长期合作伙伴,主营产品:日化产品','李立国','13323566543','广西南宁市秀厢大道42-1号','0771-98861134',1,'2020-03-21 19:52:07',NULL,NULL),(10,'JS_GYS002','南京火头军信息技术有限公司','长期合作伙伴,主营产品:不锈钢厨具等','陈女士','13098992113','江苏省南京市浦口区浦口大道1号新城总部大厦A座903室','025-86223345',1,'2020-03-25 16:52:07',NULL,NULL),(11,'GZ_GYS003','广州市白云区美星五金制品厂','长期合作伙伴,主营产品:海绵床垫、坐垫、靠垫、海绵枕头、头枕等','梁天','13562276775','广州市白云区钟落潭镇福龙路20号','020-85542231',1,'2020-01-21 06:12:17',NULL,NULL),(12,'BJ_GYS004','北京隆盛日化科技','长期合作伙伴,主营产品:日化环保清洗剂,家居洗涤专卖、洗涤用品网、墙体除霉剂、墙面霉菌清除剂等','孙欣','13689865678','北京市大兴区旧宫','010-35576786',1,'2020-01-21 12:51:11',NULL,NULL),(13,'SD_GYS001','山东豪克华光联合发展有限公司','长期合作伙伴,主营产品:洗衣皂、洗衣粉、洗衣液、洗洁精、消杀类、香皂等','吴洪转','13245468787','山东济阳济北工业区仁和街21号','0531-53362445',1,'2020-01-28 10:52:07',NULL,NULL),(14,'JS_GYS003','无锡喜源坤商行','长期合作伙伴,主营产品:日化品批销','周一清','18567674532','江苏无锡盛岸西路','0510-32274422',1,'2020-04-23 11:11:11',NULL,NULL),(15,'ZJ_GYS002','乐摆日用品厂','长期合作伙伴,主营产品:各种中、高档塑料杯,塑料乐扣水杯(密封杯)、保鲜杯(保鲜盒)、广告杯、礼品杯','王世杰','13212331567','浙江省金华市义乌市义东路','0579-34452321',1,'2020-06-22 10:01:30',NULL,NULL);
    向smbms_role表插入数据
    insert into `smbms_role`(`id`,`roleCode`,`roleName`,`createdBy`,`creationDate`,`modifyBy`,`modifyDate`) values (1,'SMBMS_ADMIN','系统管理员',1,'2020-01-01 00:00:00',NULL,NULL),(2,'SMBMS_MANAGER','经理',1,'2020-02-02 00:01:00',NULL,NULL),(3,'SMBMS_EMPLOYEE','普通员工',1,'2020-02-03 00:00:00',NULL,NULL);
    向smbms_user表插入数据
    insert into `smbms_user`(`id`,`userCode`,`userName`,`userPassword`,`gender`,`birthday`,`phone`,`address`,`userRole`,`createdBy`,`creationDate`,`modifyBy`,`modifyDate`) values (1,'admin','系统管理员','1234567',1,'1983-10-10','13688889999','山东省日照市东港区成府路207号',1,1,'2020-03-21 16:52:07',NULL,NULL),(2,'liming','李明','0000000',2,'1983-12-10','13688884457','山东省日照市东港区前门东大街9号',2,1,'2020-03-01 00:00:00',NULL,NULL),(5,'hanlubiao','韩路彪','0000000',2,'2001-06-05','18567542321','山东省日照市东港区北辰中心12号',2,1,'2020-02-11 19:52:09',NULL,NULL),(6,'zhanghua','张华','0000000',1,'1980-06-15','13544561111','山东省日照市东港区学院路61号',3,1,'2020-02-11 10:51:17',NULL,NULL),(7,'wangyang','王洋','0000000',2,'2001-12-31','13444561124','山东省青岛市三二二区西二旗辉煌国际16层',3,1,'2020-06-11 19:09:07',NULL,NULL),(8,'zhaoyan','赵燕','0000000',1,'1999-03-07','18098764545','山东省青岛市东科区回龙观小区10号楼',3,1,'2020-04-21 13:54:07',NULL,NULL),(10,'sunlei','孙磊','0000000',2,'1998-01-04','13387676765','山东省日照市朝阳区管庄新月小区12楼',3,1,'2020-05-06 10:52:07',NULL,NULL),(11,'sunxing','孙兴','0000000',2,'1997-03-12','13367890900','北京市朝阳区建国门南大街10号',3,1,'2020-01-09 16:51:17',NULL,NULL),(12,'zhangchen','张晨','0000000',1,'1986-03-28','18098765434','朝阳区管庄路口北柏林爱乐三期13号楼',3,1,'2019-06-09 05:52:37',1,'2020-04-14 14:15:36'),(13,'dengchao','邓超','0000000',2,'1981-11-04','13689674534','北京市海淀区北航家属院10号楼',3,1,'2020-07-01 08:02:47',NULL,NULL),(14,'yangguo','杨过','0000000',2,'1989-01-01','13388886623','北京市朝阳区北苑家园茉莉园20号楼',3,1,'2020-02-01 03:52:07',NULL,NULL),(15,'zhaomin','赵敏','0000000',1,'1989-12-04','18099897657','山东省临沂市昌平区天通苑3区12号楼',2,1,'2020-01-12 12:02:12',NULL,NULL);
    此外,本系统中所用到的用户性别和用户身份代码如表3.5.1至表3.5.2所示。
    用户性别代码表



    代码
    说明




    1



    2




    用户身份代码



    代码
    说明




    1
    系统管理员


    2
    经理


    3
    普通员工



    4 各功能模块的设计与实现4.1 系统开发条件4.1.1 开发语言系统使用的开发语言是Java。Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程等特点。Java可以编写桌面应用程序、Web应用程序、分布式系统应用程序等。正是因为Java语言拥有如此诸多的优秀特性,所以我们选择了它作为开发超市订单管理系统,使得整个开发、调试过程更加高效。
    4.1.2 开发框架超市订单管理系统以SSM架构作为支撑,分为表现层、业务层和持久层三层,实现后台数据更新。该架构由Spring MVC、Spring和MyBatis三个开源框架整合而成,用于开发结构合理,性能优越,代码健壮的应用程序。

    4.1.3 前端框架由于本系统是Web应用,所以使用了HTML5+CSS3+JavaScript的方式实现前端页面。实现过程中参考了Bootstrap前端开发框架。Bootstrap是Twitter退出的一个用于前端开发的开源工具包。在设计前端页面时,参考了Bootstrap的相关开源代码。
    4.1.4 集成开发环境编程所使用的集成开发环境是Eclipse,是著名的跨平台的自由集成开发环境(IDE)。Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。本次系统便选用了Eclipse作为开发平台。
    4.1.5 Web应用服务器Tomcat由Apache、Sun和其他一些公司及个人共同开发而成。由于有了Sun的参与和支持,最新的Servlet和JSP规范可以在Tomcat中得到体现。因为Tomcat技术先进、性能稳定,因而成为目前比较流行的Web应用服务器。本次系统选用的便是Tomcat作为应用服务器。
    4.1.6 数据库管理系统本系统使用的数据库管理系统是MySQL Community。MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发。在WEB应用方面,MySQL是最好的RDBMS (Relational Database Management System,关系数据库管理系统)应用软件。
    系统中的数据库以及数据库中的所有关系模式都使用MySQL进行处理。
    4.2 用户界面设计完成数据库创建和功能说明以后,我们进行下一步工作,即设计用户界面,完成了系统要求的 5 项主要功能。
    我们把超市订单管理系统的窗体分成5个主要部分,如下图所示。
    4.2.1 订单管理
    4.2.2 供应商管理
    4.2.3 用户管理
    4.2.4 修改密码
    4.2.5 登录注销
    4.3 功能模块说明5.3.1 订单信息添加、查询、修改与删除订单信息查看:为了对订单浏览信息,能够实现浏览的功能是十分必要的。管理员输入需要搜索的相应信息,点击查看按钮后系统将寻找到的数据展示到网页中。

    订单信息添加:作为超市订单管理系统,订单信息的管理是很重要的。每当采购部门增加新的订单时,订单信息就要增加。超市也可能因为其它原因增加订单信息,订单添加模块都可以做出快捷的解决方案。管理员输入相应的信息,点击提交后系统将数据保存到数据库中。

    订单信息修改:根据订单编号可以查询订单详细信息,然后修改订单的所有信息。系统从数据库中读取数据并显示到页面上,管理员修改数据后,点击修改按钮,系统将更新表中的数据。

    订单信息删除:根据订单编号可以删除该订单的信息。管理员选择需要删除订单名称并点击删除按钮,系统将从数据库中删除相应数据。
    订单信息查询:在成千上万种商品种,如果人为寻找某一个商品肯定是不可能的,只有通过商品信息查询模块才能为用户或管理人员解决这个难题。根据订单名称可以查询该订单的信息。管理员输入订单名称并点击查询按钮,系统将从数据库中查询相应的数据并显示到页面上。

    5.3.2 供应商信息添加、查询、修改与删除供应商查询界面:供应商查询界面提供了供应商的信息,可根据供应商名称的关键字进行筛选查询,并提供了添加供应商、查看供应商详细信息、修改供应商信息、删除供应商的功能。

    供应商查看详情界面:在供应商查询界面点击具体供应商操作列表的查看按钮,可以查看供应商的具体信息,包括:供货商编码、供货商名称、详细描述、联系人、联系电话、地址、微信。

    供应商修改页面:若供应商信息变动,管理员可通过供应商信息修改功能对供应商信息进行更新,更新后的数据将保存到数据库中。

    商品供应商信息删除:企业倒闭或者经营策略的改变,当它对超市商品的供应没有作用时,商品供应商厂家信息的删除是正常的。管理员输入供应商名称查询数据表中的数据并显示到页面上,点击删除后系统将表中的相应数据删除。
    供应商添加界面:与供应商达成交易后,管理员在供应商添加页面填写供应商具体信息,填写完毕点击提交,添加后的数据将保存到数据库中。

    5.3.3 用户信息添加、查询、修改与删除用户管理页面:通过输入用户名和身份查询用户。当不记得用户名的具体名字时,只输入用户名的其中一个字,会检索出所有带这个字的用户,方便管理员查询管理。点击右边链接添加用户,会连接到相关网页添加用户信息。点击操作里的查看、修改等可以进行相应的改、删、查操作。

    用户信息删除:当企业员工离职时,或者经过一段时间后,会发现用户表中一些信息时无用的,用户删除模块可以解决这样的问题。
    添加用户信息:填写用户相关信息,下面有两个按钮,可以选择重置或者提交。

    5.3.4 修改密码为了系统的安全,用户的应该只有用户个人才能修改,这不仅保证了整个公司的利益也保护了个人隐私。用户在输入相应的用户编号,填写旧密码以及新密码后,点击提交,重置密码成功。发现输入错误时,可以手动删除或者点击重置按钮,重新填写。

    修改用户密码成功后,会弹出修改用户密码成功页面,如图4.3.14所示。

    5.3.5 登录/注销输入用户名以及用户密码登录进入超市订单管理界面,可以查看管理信息。管理员可以对相关数据进行增、改、查等操作,也可以注销退出系统。
    5 实训总结5.1 所遇困难在实现本系统时遇到的困难主要体现在两个方面,一是系统的前端页面的设计,二是怎样Web与数据库实现交互。
    系统前端页面的设计困难的解决是通过参考著名的前端框架Bootstrap实现的。Bootstrap框架提供了许多精美的组建、布局,还开放了源代码供参考。在此基础上我们还加入了一些利用JavaScript代码实现的美化效果,使得前端设计更加美观。
    实体Web与数据库交互的解决得益于SSM框架的三层Spring MVC、Spring和MyBatis,能够分离处理数据库与Web层的视图,从而达到交互的目的。
    此外,在编写后端的时候,变量的大小写、系统配置也是困难重重。好在,在反复编写之后,迅速熟悉的技巧,能够让页面自由切换。系统配置更是反复在网上求证,得以解决。
    5.2 实验心得这一次合作开发超市订单管理系统,从开始选择课题的困惑到最终完成了一个我们还算满意的作品,使我学到了很多东西。从设计数据库到编写后台代码,链接数据库,在网页上显示,令人印象深刻。反复查阅资料,启动Tomcat到凌晨0点,都是藏着对这次项目的努力。其实,从一开始选择哪个题目是否用SSM框架来开发我一直也犹豫过,像国内势头正旺的ThinkPHP,易学易用,完善的中文开发文档,遇到问题或者bug可以非常容易的在中文社区得到解答。但是我最后选择了SSM框架,不仅仅因为它广泛,而是我希望能够挑战自己。经过这一个周的磨练,我最大的收获除了学到了真正可以应用的知识外,更重要的是学会了项目合作开发的经验。
    13 留言 2020-08-05 15:32:05 奖励46点积分
  • 安装Linux的交叉编译工具链

    1、linux中装软件的特点linux中安装软件比windows中复杂。linux中安装软件一般有以下几种方法:

    第一种:在线安装。譬如ubuntu中使用apt-get install vim来安装vim软件
    第二种:自己下载安装包来安装。这种方式的缺陷就是你不知道你下载的安装包和你的系统是否匹配
    第三种:最装逼的一种方式,就是源代码安装

    总结:我们安装交叉编译工具链(arm-linux-gcc)实际采用第二种安装方式。
    2、s5pv210交叉编译工具链版本的选择
    解压后形式: arm-2009q3(三星官方)
    解压前形式:arm-2009q3.tar.bz2

    3、交叉编译工具链的安装步骤
    步骤1:打开虚拟机,在/usr/local/下创建/usr/local/arm文件夹【注意需要用sudo才能创建,否则不能创建,如下图】


    步骤2:先将安装包 arm-2009q3.tar.bz2从Windows中弄到ubuntu中去(此处使用共享文件夹)
    步骤3:复制。在ubuntu中进入到/usr/local/arm/所在的目录, 通过命令sudo cp /mnt/hgfs/linuxshare/arm-2009q3.tar.bz2 ./将arm-2009q3.tar.bz2复制到arm目录下




    从上图可以看到,已经复制成功。【注意】这里需要使用sudo权限如上图操作,且需要特别注意格式,注意点号“.”后面需要有“/”,即用“./”表示当前目录。

    步骤4:解压。复制结束之后,在/usr/local/arm/目录下使用tar -jxv命令解压安转包,解压指令如下:tar -jxvf arm-2009q3.tar.bz2。按回车键后让ubnutu自动安装直到安装完毕(真正的应用程序安装在/usr/local/arm/arm-2009q3/bin目录下),遇到一个问题,使用解压命令tar -jxvf arm-2009q3.tar.bz2无法解压成功,怎么办呢?解决方法:在解压命令前面加上sudo即可解决。解压成功的标志是,在arm目录下可以看到arm-2009q3这个文件夹,如下图:


    到此为止交叉编译链已经安装成功,因为这是一个绿色软件,解压后可以直接使用。真正的应用程序的安装目录下(/usr/local/arm/arm-2009q3/bin)
    【补充】使用命令:sudo su root 可以进入root权限

    步骤5:到真正的应用程序的安装目录下(也就是/usr/local/arm/arm-2009q3/bin),进入目录看到如下:


    上面看到的绿色的“arm-none-linux-gnueabi-gcc”便是交叉工具编译链,这是编写这个交叉工具编译链的创造者起的名字,但是为了方便我们习惯把它缩短一些,统称叫“arm-linux-gcc”,这也是后面会谈到的“为工具链创建arm-linux-xxx符号链接”
    4、安装后的测试安装完之后现在测试一下安装的交叉工具编译链能不能用。到目录/usr/local/arm/arm-2009q3/bin,执行一下安装的编译链。
    执行方法是:
    ./arm-none-linux-gnueabi-gcc -v
    (说明:-v是参数,用来测试所安装的交叉工具编译链的版本)
    执行后可以得到一长串输出,其中有“gcc version 4.4.1 ”字样,即表示安装成功。
    5、为工具链创建arm-linux-xxx符号链接sudo进入管理员权限后 ln arm-none-linux-gnueabi-addr2line -s arm-linux-addr2line
    【注意:上面用ln生成软连接是需要在管理员权限才可以】,生成的软连接(好比快捷方式)是左边蓝色一排

    6、环境变量的意义环境变量就是操作系统的全局变量。每一个环境变量对操作系统来说都是唯一的,名字和所代表的意义都是唯一的。linux系统可以有很多个环境变量。其中有一部分是linux系统自带的,还有一些是我们自己来扩充的。我们这里涉及到的一个环境变量是 PATH。PATH这个环境变量是系统自带的,它的含义就是系统在查找可执行程序时会搜索的路径范围。
    【注意】需要在root用户下,在根目录上使用 echo $PATH 查看路径。
    7、将工具链导出到环境变量export PATH=/usr/local/arm/arm-2009q3/bin:$PATH
    在一个终端中执行以上命令后,该终端中就可以直接使用arm-linux-gcc了,但是只要关掉这个终端再另外打开一个立马就不行了。原因是我们本次终端中执行时的操作只是针对本终端,以后再打开的终端并未被执行过这个命令所以没导出。
    解决方案:如果要每次打开终端都可以看到这个环境变量,在~/.bashrc中,添加 export PATH=/usr/local/arm/arm-2009q3/bin:$PATH 即可。
    注意:我们导出这个环境变量是在当前用户,如果你登录时在其他用户下是没用的。
    【linux中的目录管理方法】我们习惯在/bin(根目录的bin)目录下目录放置一些【系统自带的用户使用】的应用程序,/sbin(根目录的sbin)目录下存放的是【系统自带的系统管理方面】的应用程序。如下两个截图分别是/bin和/sbin中的部分截取,只是为了让大家看清楚linux目录管理的方法。


    那我们装软件放在哪里?一般都在/usr目录下。我们安装arm-linux-gcc,就在/usr/local/底下创建一个arm文件夹,然后装到将要安装的软件装在arm里面。之所以起名为arm是因为我们现在做的都是arm开发。
    0 留言 2021-04-13 08:55:50 奖励34点积分
  • mybatis学习笔记(1)

    环境:

    jdk1.8
    mysql 8.0
    maven 3.6.3
    idea

    回顾:

    jdbc
    mysql
    java基础
    maven
    junit
    ssm框架:配置文件的

    什么是 MyBatis?

    MyBatis 是一款优秀的持久层框架
    它支持自定义 SQL、存储过程以及高级映射
    MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
    MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录

    如何获得mybatis?

    持久层
    数据持久化:持久化是将程序的数据在持久状态和瞬时状态转化的过程
    内存:断电即失
    数据库(jdbc)io文件持久化

    为什么要持久化?

    有一些对象,不能让他丢掉
    内存太贵了
    持久层

    Dao层,service层…
    完成持久化工作的代码块
    层是界限十分明显的

    为什么需要mybatis?

    方便
    传统的jdbc太复杂了,为了简化。自动化操作
    帮助程序员将数据存入到数据库中
    不用mybatis也可以。只是用了更容易上手。技术没有高低之分
    可以解除SQL与程序代码的耦合,sql和代码分离,提高可维护性
    提供xml标签,支持编写动态sql
    最重要的一点:使用的人多!
    spring springmvc springboot

    第一个mybatis程序
    思路:搭建环境–导入mybatis —编写代码–测试
    搭建数据库
    CREATE DATABASE `mybatis`USE mybatisCREATE TABLE `user`(id INT NOT NULL,`name` VARCHAR(10) DEFAULT NULL,pwd VARCHAR(10) DEFAULT NULL,PRIMARY KEY (id))ENGINE=INNODB DEFAULT CHARSET =utf8INSERT INTO `user` (id,`name`,pwd) VALUES(1,'lilubao','123456'),(2,'lilu','123'),(3,'bao','456')
    新建一个普通的maven项目,导入依赖
    <dependencies><!-- /mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.23</version> </dependency><!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency><!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> </dependencies>
    编写mybatis核心配置文件
    <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><!----><configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT&useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments></configuration>
    编写工具类
    package com.lilubao.utils;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSession;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import java.io.IOException;import java.io.InputStream;public class mybatisUtils { private static SqlSessionFactory sqlSessionFactory;//提升作用域 static{ try { //使用mybatis的第一步:获取sqlSessionFactory的对象 加载资源 String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例 //SqlSession 提供了在数据库执行 SQL 命令所需的所有方法 // 创建一个能执行sql的对象 public static SqlSession getSqlSession(){ return sqlSessionFactory.openSession(); }}
    编写代码
    实体类
    package com.lilubao.pojo; //实体类public class user { private int id; private String name; private String pwd; public user() { } public user(int id, String name, String pwd) { this.id = id; this.name = name; this.pwd = pwd; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPwd() { return pwd; } public void setPwd(String pwd) { this.pwd = pwd; } @Override public String toString() { return "user{" + "id=" + id + ", name='" + name + '\'' + ", pwd='" + pwd + '\'' + '}'; }}
    dao接口
    package com.lilubao.dao;import com.lilubao.pojo.user;import java.util.List;public interface UserDao { List<user> getUserList();}
    接口实现类由原来的UserDaolmpl转变为一个Mapper配置文件
    <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><!--namespace ::mapper接口--><mapper namespace="com.lilubao.dao.UserDao"><!--id 对应前面的方法名字--> <select id="getUserList" resultType="com.lilubao.pojo.user"> select * from mybatis.user </select></mapper>
    junit测试
    注意点:org.apache.ibatis.binding.BindingException: Type interface com.lilubao.dao.UserDao is not known to the MapperRegistry.
    只需要在在核心配置文件中注册mappers
    package com.lilubao.dao;import com.lilubao.pojo.user;import com.lilubao.utils.mybatisUtils;import org.apache.ibatis.session.SqlSession;import org.junit.Test;import java.util.List;public class UserDaoTest { @Test public void test(){ //第一步 获得sqlSession对象 SqlSession sqlSession = mybatisUtils.getSqlSession(); //执行sql UserDao userDao = sqlSession.getMapper(UserDao.class); List<user> userList = userDao.getUserList(); for (user user : userList) { System.out.println(user); } //关闭sqlSession sqlSession.close(); }}
    0 留言 2021-04-10 11:04:33 奖励32点积分
  • 机器学习【新篇章】- Introduction & Linear Regression with One Variable

    前文链接:https://write-bug.com/article/2700.html
    碎碎念距离上次总结,已是两年前,两年前的总结只注重微观性,逻辑性不强。从大数据的采集、存储、数据预处理、计算(简单机器学习算法)、常用评判标准的一条龙项目架构做了概括。但每个知识点都是分散的,虽然介绍了单个框架的深入原理,用了入门级的代码实现功能,介绍使用方法。这些框架每一个都可以钻的很深,一不小心就会掉入漩涡,无法从足够的高度观察工程,浪费时间,徒增烦恼。
    由上面的架构概括,可观察到其中的每一个步骤所产生的价值、业务,甚至可以说是选择一个方向作为兴趣发展为你的专长,在之前的推荐系统项目中,虽然是单机版,但已经很好的帮助串起整个项目的工程和业务,这对你以后做其中任何一个节点的深入专业,都是有好处的。推荐系统把我引入到了机器学习的大门,里面NLP/CV两个方向所实现的功能更让人叹为观止。
    学习时,我们总有一种系统学习的思想,好像老师划分考试范围,超出这个知识树的范围都不是我要学习的,缺乏自主学习能力,有人把这个称之为学生思维,但其实生活中所有知识都是散碎的,时刻创新的,需要我们不断地去吸收、消化,再输出。循环往复。
    从这里开始,将参考吴恩达视频从头介绍机器学习、深度学习,这次会尽可能简洁的写下每个步骤所产生的逻辑,用numpy、pandas、matlab、pytorch/tensflow、sklearn等学习库介绍并实现每个算法。
    学习的难点在于,不是拥有这些学习算法,而是针对不同的问题如何恰当地使用不同的算法组合(解决方案)。
    机器学习的应用之前项目所用到的机器学习领域的应用属于数据挖掘案例,近年由于网络信息和自动化技术的爆炸性增长,意味着产生了史上最大的数据集。web用户点击数据(即用户行为数据)、电子医疗记录、DNA基因数据序列等等都可以通过数据挖掘来给予用户最好的服务。
    而除此之外,还有更多有趣又简单的应用:无人驾驶、item分类、web搜索、手写识别等等,计算机语言处理NLP、计算机视觉CV也都应用了机器学习。
    机器学习定义
    吴恩达视频中,有个有趣的押韵定义:

    一个程序被认为能从经验E中学习,解决任务T,达到性能度量值P当且仅当有了经验E后经过P评判,程序在处理T时的性能有所提升即计算机程序从经验E中学习某些类型的任务T和性能度量P,如果它在任务T中的性能(以P度量)随着经验E的提高而提高
    在无需具体的编程规则的条件下,给予计算机以学习的能力

    假如对于邮件分类问题:T为邮件分类,E为观察用户是否标记垃圾邮件,P为正确归类邮件的比例。
    学习算法主要分为两种类型的学习算法:监督学习、无监督学习。
    简单地说:

    监督学习算法时指我们将教计算机如何完成任务
    无监督学习算法指我们打算让它自己学习


    监督学习举例预测房价问题
    x:房子面积
    y:房价

    我们把收集到的真实房价数据映射在直角坐标系中:

    假设我们手里有一个房子面积是750平方英尺,如何知道卖多少钱呢?
    应用学习算法,在图中这组数据上拟合一条直线,或者曲线,此时我们可将面积直接代入一次或二次方程算出房价$200k。
    此例子中的数据集,由“正确答案“组成,而我们想预测房子价格的问题被称为“回归问题”,即 试推测一系列连续值属性。
    推测乳腺癌良性与否问题
    x:肿瘤大小
    y:良性0/恶性1

    同样映射入坐标系后,根据新数据的肿瘤大小预测是否为良性的问题。

    以上两种数据描绘方式,第一种是根据肿瘤大小预测离散值的结果,第二种是根据肿瘤大小和患者年龄预测离散值的结果,这类问题被称为“分类问题”,即 试推测离散的输出值。
    当然在机器学习问题中,肯定遇到不止一种特征的问题,比如患者的年龄(第二种描绘方式)、肿瘤密度、形状等都是决定良性与否的特征。此时我们就要找到一种算法,即使有无限多的特征都可以处理。比如支持向量机……
    以上:

    介绍了监督学习,即 根据真实样本数据做出预测
    介绍了回归问题,即预测连续的输出
    介绍了分类问题,即预测离散的输出

    无监督学习举例不同于监督学习,无监督学习的数据无任何标签,我们不知如何处理,只是一个数据集。
    应用:Google新闻主题自动聚类(这里聚类只是无监督学习其中的一个算法),DNA微观数据聚类,用户市场分类、天文数据分析等。
    鸡尾酒宴问题宴会中有很多人,在房间内放置两个话筒录音,那么多人的声音就会重叠在一起,声音大小不同,音色不同。此时,就可通过无监督学习算法分离出不同人的声音。
    以上,介绍了无监督学习,想象一下,如果没有这类算法,我们将制定大量的专业知识、规则、链接大量的java库等等对数据做处理,而这个只需要让机器自动学出规律。
    单变量线性回归第一个学习算法:线性回归算法。
    下面将介绍一些术语和表达字母:
    之前介绍的回归与分类例子,都有一个数据集称为训练集(Training Set),其中一条为训练样本

    m:训练样本的数目,即训练集中实例的数量
    x:特征/输入变量


    y:目标变量/输出变量
    (x,y):训练集中实例/一条训练样本
    (x^i,y^i):第 i 个观察样本
    h:学习算法的函数(解决方案),也称假设(hypothesis)


    将训练集“喂”给学习算法得到函数h,将变量x输入h得到预测y。
    问题1:我们如何由学习算法得到h?
    假设我们的h(x) = θ0 +θ1x ,因为只有一个x特征/输入变量,所以叫单变量线性回归问题。
    问题2:我们如何确定函数h(x)是否拟合Training Set?如何确定拟合时的θ参数?

    假设 h(x)初始化参数θ0=0,θ1=0.5,如图所示。
    初始化参数描绘出的图和训练集的拟合程度相差很大,即模型h(x)所预测的值与训练集中实际值之间的差距,即建模误差(modeling error)。
    此时,我们的目标就是让预测更准确,也就是让建模误差的平方和最小时的模型参数。
    即代价函数:

    最小。
    这里通过三维坐标θ0,θ1和J(θ0,θ1)绘制等高线图:

    此时,可以在三维空间中找到一个最低点,就是最佳参数:θ0,θ1。
    这个代价函数被称为平方误差代价函数,这个代价函数可解决大多数回归问题,作为常用手段使用。
    通过以上两个问题和介绍:

    介绍了机器学习算法的使用术语
    了解了模型函数h
    了解了平方误差代价函数

    代价函数前面我们理解了代价函数是做什么的。接下来,我们将继续介绍目标:代价函数和如何自动使代价函数最小化θ参数的值。

    不管是这里的二维空间表达的代价函数J,还是三维空间表达的等高线图,我们最后都需要他取最小值时的参数θ0,θ1 的值。
    问题:如何找到一种有效的算法,可以自动求出代价函数J 的最小值呢?
    梯度下降是一个用来求函数最小值的算法,可求出代价函数J(θ0,θ1)的最小值。
    梯度下降思想1
    随机选取一个参数组合(θ0,θ1……θn),计算代价函数
    再寻找下一组可以让代价函数值下降更多的参数组合
    反复迭代到一个局部最小值(local minimum)

    由于没有尝试所有的参数组合,所以不能确定得到的最小值是否是全局最小值(global minimum),选取不同的初始参数组合,就可找到不同的局部最小值。
    思想2想象站在山顶,在梯度下降算法中,我们需要观看周围360°,找出最快下山方向(θ偏导数),走出一小步(学习率),再次观察最佳方向,走出一小步,重复以上,直到你接近局部最低点位置,也就是你所在的位置可能是个坑。

    批量梯度下降(batch gradient descent)公式:

    (for j=0 & j=1)
    α为学习率(learning rate),即走多大的步子。决定了我们沿着让代价函数下降程度最大的方向向下的步子有多大。
    【注:】如何α太大或太小会怎样?
    α太小,下降会很慢,需要迭代很多次才能到最低点
    α太大,梯度下降法可能会越过最低点,甚至无法收敛,直至离最低点越来越远


    是代价函数的偏导数,决定了向什么方向下山。
    【注:】
    如果一开始θ1就初始化在局部最低点,意味着局部最优点的导数等于0,θ1不更新
    当导数接近最低点时,导数值自动变小,所以移动幅度会自动变小,而在局部最低时导数等于0,或者直至移动幅度非常小时停止(可设阈值)。所以不需要额外减小a


    问题1:

    的含义是什么?


    问题2:当我们谈论梯度下降时,意思时每次下降要更新所有参数,这里j取0和1,但对不同参数求导时,需要用到另外的参数,那么如何才能同时更新所有参数呢?
    代码实现上,我们应先计算等式右边的公式,再同时更新参数θ。

    以上,就是梯度下降的介绍,它可以用来最小化任何代价函数,不只是线性回归。
    结合梯度下降法与平方代价函数,得出第一个学习算法:线性回归算法。
    公式对比:

    用于线性回归的梯度下降:

    这种梯度下降算法,有时也成为批量梯度下降。
    即每一步更新参数时,都需要对所有训练样本计算(求导求和),事实上,也有其它类型的梯度下降法不是批量型,不考虑整个训练集,只关注小的子集,以后介绍。
    以上,就是此章节的内容。
    关键词: 机器学习、术语、监督学习、无监督学习、回归、分类、单变量线性回归、代价函数、梯度下降
    实践
    参考黄博士codehttps://github.com/fengdu78/Coursera-ML-AndrewNg-Notes/blob/master/code/ex1-linear%20regression/1.linear_regreesion_v1.ipynb
    参考褚博士pytorch视频链接:https://pan.baidu.com/s/1kxWaWik2UyvTYWnmXWEpqQ提取码:gvyu
    参考吴恩达机器学习视频https://www.bilibili.com/video/BV164411S78V

    其他的手撕代码后续更新
    更新(代码地址):https://github.com/duhaichao/ML-code
    0 留言 2021-04-07 08:49:51 奖励40点积分
  • JDK的安装到配置path

    JDK的安装到配置path首先声明:后缀为 .java 的文件的编译运行需要执行 jdk 安装路径的 bin 目录中的 javac 文件和 java 文件。
    1. 下载推荐去: 链接 下载( jdk1.8 64 位 )
    一定要注意下载和自己电脑位数匹配的版本:

    X86 —— 32位OS
    X64 —— 64位OS

    因为网下载需要注册,有点麻烦!
    2. 下载完成后,安装jdk(注意:安装的路径)下一步,下一步,下一步,……完成。
    3. 测试jdk是否安装成功
    用win+R快捷键打开 cmd命令行窗口
    进入安装路径的bin目录下 cd C:\Program Files\Java\jdk1.8.0_131\bin(此路径为默认安装路径)
    输入命令 javac 敲回车后,会出现一大堆



    再输入命令 java 敲回车后,又会出现一大堆


    恭喜你,jdk已经安装完成!
    4. 问配置path是必须的吗?我认为 不是必须的,但是需要配置。现在我们来分析一下以下几种情况:
    情况一
    将写好的 .java 复制粘贴到 jdk 的安装的 bin 目录下
    win+R进入命令行,进入安装路径的bin目录下:cd C:\Program Files\Java\jdk1.8.0_131\bin(此路径为默认安装路径)
    注意注意:要用管理员进入命令行(打开 开始 按钮 附件 找到命令行提示符 →右键→以管理员身份运行)

    情况二
    新编辑好的 .java 文件没有放到jdk安装的bin路径下怎么办?

    复制粘贴过去?天哪,这样的话 bin目录里面该会乱成什么样子,难以想象。所以针对这种情况 ,微软的工程师想出了一个办法:
    解决办法:设置path路径(设置一个全局变量)

    计算机 → 属性 →高级设置



    点击环境变量


    在系统变量里面找到 Path


    在path路径的结尾添加一个英文的 ;,然后将jdk安装的bin目录的路径 C:\Program Files\Java\jdk1.8.0_131\bin(此路径为默认安装路径)粘贴到 ; 后边,然后确定,确定就ok了
    接下来,再以管理员身份打开命令行,cd进入到自己放 .java 文件的路径



    恭喜恭喜 path配置完成喽!
    心得:不会了就去百度,没有什么问题是不能解决的。
    1 留言 2021-04-06 13:22:57 奖励36点积分
  • C语言/ARM嵌入式-V4L视频监控系统

    摘 要随着数码相机和互联网的普及,使得人们的生活方式发生了改变。摄像头软件成为日常应用中必可少的应用软件之一,本次课程设计利用QT 设计了一款基于嵌入式视频服务器的监控系统,在linux2.6.30.4的内核基础上移植V4L2驱动模块并使用其API接口对摄像头进行设置和对所监控对象实时数据采集。系统采用TQ2440 开发板为硬件平台,在其上搭建LINUX 系统的网络视频服务器,用QT 为用户图形界面开发了客户端软件。客户端和服务端之间通过Socket通信,实现视频监控。其中在客户端连接上服务端之后,可以服务端发来的数据处理后作为图像显示在界面,提供了截图的功能、保存截图的功能。
    关键词:Linux QT;通信;视频监控;V4L2
    一、设计内容与要求1.1 基础题设计内容及要求
    编写程序将数组内容倒置a[]=”123456789”
    创建两线程,A线程循环打印数组a[100],B线程循环将数组成员+1,要求利用互斥锁,使每次输出a[0]==a[99]
    通过Makefile,将project中的两个.c编译成.a,另一个.c调用.a的函数,要求实现静态库的生成和调用,运行结果正确
    1.2 V4L视频监控系统设计内容及要求完成videodev.o驱动程序并编译成功
    将驱动程序复制到用户目录
    测试并运行成功摄像头监控

    1.3 设计的实现方案在实现的过程中,我们首先要在服务器端通过videodev.o驱动程序用于打开摄像头,其方法试是我们创建数据缓冲区和一个线程,这个线程用于采集视频,通过在视频采集函数中,将套接字加入socket中,监控数据中是否含有套接字,若有则创建另一个用于向客服端通过socket发送采集视频的线程,然后我们要运用虚拟机中的QT编译工具,对要实现的视频摄像头的基本界面进行设计,布局完成之后,再对各个模块进行进行信号与槽函数的实现,最后再对整体进行优化设计,使得编写好的软件能够顺利流畅的运行。
    二、总体设计2.1 视频监控系统的总体设计Qt是一个1991年由奇趣科技开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程式,也可用于开发非GUI程式,比如控制台工具和服务器。Qt是面向对象的框架,使用特殊的代码生成扩展(称为元对象编译器(Meta Object Compiler, moc))以及一些宏,易于扩展,允许组件编程。服务器使用基于ARM9 的Qt2440开发板为硬件搭载平台和linux系统内核的软件平台。此视频监控系统主要由服务器、摄像头、客户端三部分模块组成。向操作系统内核移植了videodev.o驱动,并使用此来驱动网络摄像头模块,服务器对所采集到的视频数据提出来,并通过网口使用TCP/IP网络协议传输方式向客户端发送含有套接字socket的视频数据。如图所示:

    2.2 客户端设计首先用QT Creator 创建文件,利用QT 工具画好整体的主界面,建立一个主窗口。然后在这个主窗口上方放置一个行编辑框用来输入服务器IP、端口号,下方进行视频监控显示。客户端主要是连接到服务器,在客户端连接上服务端之后,将服务器传过来的数据进行处理,将数据作为JDPG图像显示在界面上。客户可以实现对图片的截取、保存。客户端总体流程框图如图所示:

    2.3 服务器端设计首先需要安装交叉编译器,将程序用arm-linux-gcc编译成适合TQ2440开发板下可运行的程序,并通过连接下载工具,使之在开发板上运行。服务器端总体流程图如图三所示:

    三、具体分析3.1 客户端具体设计3.1.1 客户端主界面设计QT 是一个支持多操作系统平台的应用程序开发框架,通过建立一个函数调用connect()函数把这个插槽和一个信号连接起来,这样就完成了一个事件和响应代码的连接。这里我们采用了多线程技术,主线程在主窗口绘图,实时显示监控视频;次线程建立TCP 连接,接收来自服务器的数据,当接收够一帧的数据后发射信号给主线程,让主线程来绘图。客户端的主要界面用到了控件labelVideo用于显示视频,btnConnect用于按钮connect,capture_btn用于按钮Captrue,显示端口和IP地址是用的txtPort和txtIP。主要界面如图所示:

    3.1.2 数据接收线程的设计我们首先初始化并建立一个TCP 连接,当连接出错时,返回错误并提示。然后通过QTcpSocket 类的bytesAvailable()函数来判断是否有数据可读,若可读则通过该函数的返回值来判断这一帧有多少数据需要读。所以客户端接受来自服务器端发来的数据,数据是由摄像头采集而来的,数据以jepg图片的格式连接,所以在客户端要做的就是将每一张图片从数据中分离出来,而后将其显示在主界面的视频浏览框内。实现流程图如图五所示:

    其实现主要代码如下:
    //读取数据void MainWindow::readMesg() { qba= tcpSocket->readAll(); for(int i = 0;i < qba.count();i++){ if(enRecv) imageBuff += qba[i]; if(lastbyte == (char)0xFF) { if(qba[i] == (char)0xD8) { qDebug()<<"START"<<endl; enRecv = true; }
    3.2 服务器端具体设计3.2.1视频采集模块的设计视频的采集模块调用V4L,实现对原始视频数据的采集,其实现过程如下:先定义两个线程,一个线程用于采集视频,通过调用函数*pthread_video来实现,其中在函数*pthread_video里面又定义两个函数,一个是用于打开视频,开始采集,第二个函数对采集到的视频保存到数据缓冲区databufer中,另外一个线程用于发送采集到的视频,也是通过调用函数*pthread_snd实现,首先等待客服端连接,如果连接成功,则将数据写到套接字newsd中。
    当数据流采集成功后,通过文件描述符集fdsr来监听,客户端是否有连接,如果有连接则通过套接字socket发送给客户端。主要的具体代码如下:
    void *pthread_video(void *arg)//视频采集函数{ pthread_detach(pthread_self());//? video_on();//打开视频,开始采集 databuf=(buf_t *)malloc(sizeof(buf_t)+buffers[0].length);//分配空间 while(1) { video();//采集数据,保存 }// video_off(); return NULL;}void video_on()//打开视频,开始采集{ enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl (fd, VIDIOC_STREAMON, &type) < 0) { printf("VIDIOC_STREAMON error\n"); // return -1; }}void *pthread_snd(void *socketsd)//采集完数据,发送数据{ pthread_detach(pthread_self());//让自己的线程不阻塞 int sd=((int )socketsd); int newsd,ret,i=0; newsd=accept(sd,NULL,NULL);//等待客服端连接, if(newsd==-1) { perror("accept"); return NULL; } while(1)//如果连接成功, { pthread_mutex_lock(&g_lock); pthread_cond_wait(&g_cond,&g_lock); write(newsd,databuf->buf,databuf->datasize);//写数据到socket文件 if(ret==-1) { printf("client is out\n"); } pthread_mutex_unlock(&g_lock); } return NULL;}
    3.2.2 摄像头模块设计本次课程设计的摄像头系统对摄像头模块使用单独线程管理。在pthread_video线程创建之前,调用videodev.o驱动接口对摄像头的格式进行设置,设置完成创建pthread_video线程,进入pthread_video线程进行视频录制。具体实现代码如下:
    struct v4l2_buffer buf;memset(&buf,0,sizeof(buf));buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMORY_MMAP; buf.index = 0;while(1) { if (ioctl(video_fd, VIDIOC_DQBUF, &buf) == -1) { return -1; } memcpy(databuf->buf,buffers[buf.index].start,buffers[buf.index].length); databuf->datasize=buf.bytesused; pthread_cond_signal(&g_cond); usleep(500); if(ioctl(video_fd,VIDIOC_QBUF,&buf)==-1){ return -1; }}
    3.2.3 视频传输模块设计本系统采用的是TCP/IP协议进行视频传输,使用socket技术奖采集到的JPEG的二进制码流传输到网络视频监控端,服务器首先建立socket流式套接字与本地端口进行绑定,然后通过客户端与服务器的通讯信息来开/关闭自己线程。主要代码如下:
    int main(){ signal(SIGPIPE,SIG_IGN);//忽略返回信息 int ret; struct sockaddr_in server_addr;//定义一个结构体变量 pthread_t tid;//线程 socklen_t addrlen;//长度 pthread_mutex_init(&g_lock,NULL);//线程互斥锁 pthread_cond_init(&g_cond,NULL);//线程互斥锁 server_addr.sin_family=AF_INET; server_addr.sin_port=htons(SERVERPORT); server_addr.sin_addr.s_addr=INADDR_ANY; //inet_pton(AF_INET,SERVERIP,&server_addr.sin_addr); addrlen=sizeof(struct sockaddr_in); int sd=socket(AF_INET,SOCK_STREAM,0);//创建套接字描述符(协议、本地地址、本地端口) if(sd==-1) { perror("socket\n"); exit(1); }// fd=open("dev/video0",O_RDWR | O_NONBLOCK,0); fd=open("/dev/video0",O_RDWR,0);//打开摄像头设备文件 if(fd==-1) { perror("open"); return 0; } ret=bind(sd,(struct sockaddr *)&server_addr,addrlen);//绑定套接字,将本地ip地址绑定到端口号,(套接字描述符、本地地址、地址长度) if(ret==-1) { perror("bind"); exit(1); } ret=listen(sd,20);//服务器最多连接20个客服端(套接字描述符,最大请求数) if(ret==-1) { perror("listen\n"); exit(1); } fd_set fdsr;//创建文件描述符集 int maxsock=sd; struct timeval tv; //mark(); localMem();//申请物理内存 ret=pthread_create(&tid,NULL,pthread_video,NULL);//创建线程采集数据 while(1) { FD_ZERO(&fdsr);//文件描述符的初始化 FD_SET(sd,&fdsr);//套接字放入文件描述符 tv.tv_sec=30; tv.tv_usec=0; ret=select(maxsock+1,&fdsr,NULL,NULL,NULL);//通过文件描述符集监听是否有连接 if(ret<0) { perror("select"); break; } else if(ret==0) { printf("timeout\n"); continue; } if(FD_ISSET(sd,&fdsr)) { ret=pthread_create(&tid,NULL,pthread_snd,((void *)sd));//9 创建线程,执行函数pthread_snd,发送数据 } } return 0;}
    四、系统测试4.1客户端测试连接好客户端与服务器,开始视频监控,监控成功图如图所示:

    五、基础题编写程序将数组内容倒置a[]=”123456789”
    程序代码实现如下:
    char a[]="0123456789"; char tmp;int i = 0,j = 0;for(i = 0,j = strlen(a)-1;i<=strlen(a)/2-1;i++,j--) { tmp = a[i]; a[i] = a[j]; a[j] = tmp; }for(i = 0;i<strlen(a);i++) printf("%c",a[i]);printf("\n");
    创建两线程,A线程循环打印数组a[100],B线程循环将数组成员+1,要求利用互斥锁,使每次输出a[0]==a[99]
    程序源代码如下:
    #include<sys/types.h>#include<sys/ipc.h>#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<string.h>pthread_mutex_t mutex;int a[3]={0,1,2};void *thrd_fun1(void *arg){ int thrd_num=(int)arg; int i; while(1) { pthread_mutex_lock(&mutex); for(i=0;i<3;i++) { printf("a[%d]=%d\n",i,a[i]); sleep(2); } pthread_mutex_unlock(&mutex); sleep(2); } pthread_mutex_destroy(&mutex); pthread_exit(NULL); }void *thrd_fun2(void *arg){ int thrd_num=(int)arg; int i; while(1) { pthread_mutex_lock(&mutex); for(i=0;i<3;i++) { a[i]++; } printf("++ finished\n"); pthread_mutex_unlock(&mutex); sleep(4); } pthread_mutex_destroy(&mutex); pthread_exit(NULL); }int main(void){ pthread_t thread[2]; int no=0,res; void *thrd_ret; res=pthread_create(&thread[0],NULL,thrd_fun1,(void*)no); if(res!=0) { printf("Create thread 1 failed\n"); exit(res); } res=pthread_create(&thread[1],NULL,thrd_fun2,(void*)no); if(res!=0) { printf("Create thread 1 failed\n"); exit(res); } for(no=0;no<2;no++) { res =pthread_join(thread[no],&thrd_ret); if(!res) { printf("Thread %d exit\n",no); } else { printf("Thread %d exit failed\n",no); } } return 0; }
    通过Makefile,将project中的两个.c编译成.a,另一个.c调用.a的函数,要求实现静态库的生成和调用,运行结果正确
    编写静态库程序thread.c如下:
    #include <stdio.h>void pf1(void){ printf("********\n"); return; }void pf2(void){ printf("#########\n"); return; }
    该程序定义两个函数,分别打印不同的内容,该程序将被编译成.a静态库。
    编写调用程序call.c如下:
    extern void pf1(void);extern void pf2(void);int main(void){ pf1(); pf2(); return 0; }
    该程序对静态库进行调用,调用静态库中的两个函数pf1和pf2。
    编写Makefile如下:
    CC=gccCPPFLAGS=-cOBJS = thread.oSOURCE = thread.cCALL_SOURCE=call.cLIB = libthread.aEXEC=callAR=arthread: ${OBJS} ${CC} -c ${SOURCE} -o ${OBJS} ${AR} rcsv $(LIB) thread.o ${CC} -o ${EXEC} ${CALL_SOURCE} -L. -lthread.PHONY : cleanclean :-rm -f ${OBJS} ${EXEC} ${LIB}
    Makefile文件实现对静态库程序编译成.a静态库,并且编译调用静态库的程序call.c为可执行文件call
    总 结通过这次比较完整的一个程序的设计,我以全身心投入的状态投入到课程设计中,甚至熬夜通宵写代码,不过这也锻炼了我的综合运用所学的基础知识,解决实际问题的能力,其中QT的学习可谓是收获颇丰,通过QT对软件整体布局的掌控,对信号与槽函数的连接,以及对函数功能的处理,都使我的能力得到了锻炼,丰富了我的经验。
    提高是有但问题还在,这一次设计让我积累了许多实际经验,也暴露出一些问题,比如想实现一个功能花了很多时间,但是最后还是半途而废,这些在以为的学习和锻炼中,希望得到解决。
    开始编写这个V4L视频监控摄像头的时候,没有头绪,在通过图书馆一些书籍的借阅后,终于对摄像头的编程有了一些了解,但这还不够,在同学耐心的指导下,终于完成了这次大作业,感谢老师和同学们的帮助。
    0 留言 2021-03-29 08:16:18 奖励60点积分
  • 基于WinPcap实现的UDP发包程序 精华

    背景一天,一位同学打电话给我说,让我帮忙开发一个基于WinPcap工具的UDP发包工具,还特地叮嘱是基于WinPcap,不要原始套接字Raw Socket。而且,时间只有一个白天,它晚上就要,而打电话给我的时候,已经临近中午了。我一听,同学一场,那就举手之劳吧。
    之前,自己就是用WinPcap开发过一些小程序,例如网卡遍历程序、Arp欺骗攻击程序等,所以,对WinPcap还算是熟悉。做这样的UDP发包程序,应该倒也不是那没事。
    现在,为了配合这篇文章的讲解,我特地对这个程序重新开发。把程序的实现原理和过程整理成文档,分享给大家。
    使用VS2013配置WinPcap开发环境程序是使用VS2013开发的,程序中要使用WinPcap工具提供的功能函数的话,就需要将对VS2013进行配置,将WinPcap库导入到程序中,现在,就先介绍WinPcap环境的配置过程:
    1.下载并安装WinPcap运行库http://www.winpcap.org/install/default.htm 。一些捕包软件会捆绑安装WinPcap,MentoHust也会附带WinPcap,这种情况下一般可以跳过此步。
    2.下载WinPcap开发包http://www.winpcap.org/devel.htm ,解压到纯英文路径。
    3.打开VS工程项目,在VS工程项目的 属性 —> VC++目录 中,包含目录 选项添加WpdPack\Include 目录,在 库目录 选项中添加 WpdPack\Lib 目录。
    4.在 属性 —> C/C++ —> 预处理器 中,添加 WPCAP 和 HAVE_REMOTE 这两个宏定义。
    5.在VS工程项目的 属性 —> 链接器 —> 输入 中,添加 wpcap.lib 和 ws2_32.lib 两个库。
    这样,就可以将WinPcap所需的库文件包含到工程项目中了。接下来,我们就开始讲解UDP发包程序的实现过程。
    实现过程1. 获取网卡设备列表首先,我们调用WinPcap函数pcap_findalldevs_ex获取设备列表信息,函数会将计算机上所有网卡设备信息返回到指向pcap_if_t结构体指针里。我们只需要对这个结构体指针进行遍历,就可以获取每个设备的详细信息。
    // 获取网卡设备列表 if (-1 == pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, szErr)) { ShowError("pcap_findalldevs_ex"); return; }
    程序将每个设备的信息显示在界面上,供用户选中使用哪个网卡进行操作。
    2. 设置网卡信息并打开网卡我们使用 pcap_open 函数来设置并打开网卡,函数中第 1 个参数stAdapterInfo. szAdapterName,表示网卡的名称;第 2 个参数 65535,表示设置保留数据包的长度,65535即每个数据包的前65535字节长度的数据被保留在缓冲区中;第 3 个参数 PCAP_OPENFLAG_DATATX_UDP 表示使用UDP协议来处理数据传输;第 4 个参数 1 ,表示以毫秒为单位的读取超时时间。读取超时用来处理,捕获一个数据包后,读操作并不必需要立即返回的情况。但这可能等待一些时间以允许捕获更多的数据包,这样用户层的一次读操作就可从操作系统的内核中读取更多的数据包。第 5 个参数为 NULL;第 6 个参数 errbuf,可以获取返回的出错信息。
    // 打开网卡 m_adhandle = pcap_open(stAdapterInfo.szAdapterName, 65535, PCAP_OPENFLAG_DATATX_UDP, 1, NULL, errbuf); if (NULL == m_adhandle) { ShowError("pcap_open"); return; }
    3. 构造UDP数据包我们根据源MAC地址、目的MAC地址、源IP地址、目的IP地址、源端口、目的端口、数据内容以及数据内容长度,构造UDP数据包。具体构造过程如下:

    首先,构造以太网帧头。
    memcpy((void*)FinalPacket, (void*)DestinationMAC, 6); memcpy((void*)(FinalPacket + 6), (void*)SourceMAC, 6); USHORT TmpType = 8; memcpy((void*)(FinalPacket + 12), (void*)&TmpType, 2);
    然后,构造IP头。
    memcpy((void*)(FinalPacket + 14), (void*)"\x45", 1); memcpy((void*)(FinalPacket + 15), (void*)"\x00", 1); TmpType = htons(TotalLen); memcpy((void*)(FinalPacket + 16), (void*)&TmpType, 2); TmpType = htons(0x1337); memcpy((void*)(FinalPacket + 18), (void*)&TmpType, 2); memcpy((void*)(FinalPacket + 20), (void*)"\x00", 1); memcpy((void*)(FinalPacket + 21), (void*)"\x00", 1); memcpy((void*)(FinalPacket + 22), (void*)"\x80", 1); memcpy((void*)(FinalPacket + 23), (void*)"\x11", 1); memcpy((void*)(FinalPacket + 24), (void*)"\x00\x00", 2); memcpy((void*)(FinalPacket + 26), (void*)&SourceIP, 4); memcpy((void*)(FinalPacket + 30), (void*)&DestIP, 4);
    接着,构造UDP头。
    TmpType = htons(SourcePort); memcpy((void*)(FinalPacket + 34), (void*)&TmpType, 2); TmpType = htons(DestinationPort); memcpy((void*)(FinalPacket + 36), (void*)&TmpType, 2); USHORT UDPTotalLen = htons(UserDataLen + 8); memcpy((void*)(FinalPacket + 38), (void*)&UDPTotalLen, 2); memcpy((void*)(FinalPacket + 42), (void*)UserData, UserDataLen);

    要注意的是,IP校验和以及UDP的校验和计算。这样,我们就可以成功构造UDP的数据包,接下来,就可以对数据包进行发送。
    4. 发送UDP数据包我们使用 pcap_sendpacket 函数发送单个数据包,第 1 个参数表示打开网卡的时候获取的句柄;第 2 个参数就是发送的数据内容;第 3 个参数表示发送数据内容的长度。注意,缓冲数据将直接发送到网络,而不会进行任何加工和处理。这就意味着应用程序需要创建一个正确的协议首部,来使这个数据包更有意义。
    // 发送数据包 if (0 != pcap_sendpacket(m_adhandle, FinalPacket, (UserDataLen + 42))) { char *szErr = pcap_geterr(m_adhandle); ShowError(szErr); return; }
    经过上面 4 步操作,便可以实现使用 WinPcap 发送 UDP 数据包了。要注意IP校验和以及UDP校验和的计算,这两个的值注意不要算错。
    程序测试我们以管理员权限运行程序,并对一个UDP程序发包,观察UDP程序能否接收到我们发包程序发送的UDP数据包。其中,UDP程序使用的是《Socket通信之UDP通信小程序》这篇文章中实现的UDP程序。
    经过测试结果,UDP程序成功接收到UDP数据包。

    总结这个程序是基于WinPcap实现的,所以,可能有很多人之前还没有接触过WinPcap方面的知识,所以,一下子使用和理解起来就比较困难。关键是耐下心来,把程序中调用到的不理解的WinPcap函数,在网上查找说明,对函数理解清晰。
    其中,要注意的是,使用WinPcap工具,需要有管理员权限。
    参考参考自《Windows黑客编程技术详解》一书
    7 留言 2018-12-20 12:12:44 奖励40点积分
  • 分布式并行计算

    分布式并行计算>

    Research Interests:

    Parallel Computing (并行计算 )Heterogeneous Computing (异构计算)Machine Learning(机器学习)

    参考书

    An Introduction to Parallel Programming ,Peter S.Pacheco,机械工业出版社, 2011.——教材
    Parallel Programming in C with MPI and OpenMP, Michael J. Quinn, McGraw-Hill Science, 2003
    Programming Massively Parallel Processors(Second Edition) David B Kirk, Wen-mei W. Hwu, Morgan Kaufmann, 2010.

    参考网站

    http://www.mpich.org/static/docs/latest/www3/
    High Performance Computing Training(LLNL) https://computing.llnl.gov/?set=training&page=index
    Deep Learning Institute(Nvidia) https://courses.nvidia.com/dli-event

    课程目标

    Fundamentals of parallel hardware and software Parallel algorithms design and analysis Parallel programming skills
    MPI(Message-Passing Interface)OpenMP(self study) CUDA OpenAcc


    关键词



    key words
    解释




    fine-grained
    细粒度


    cparse-grained
    粗粒度


    ILP
    Instruction-Level Parallelism 指令级并行


    TLP
    Thread-Level Parallelism 线程级并行



    分布式概念
    Parallel computing:
    the use of two or more processors (computers), usually within a single system, working simultaneously to solve a single problem.
    Distributed computing:
    any computing that involves multiple computers remote from each other that each have a role in a computation problem or information processing.

    来源: 企鹅号-架构师技术联盟,并行计算与分布式计算区别与联系,腾讯云,https://cloud.tencent.com/developer/news/324518
    A parallel computer is a multiple-processor computer system supporting parallel programming.

    Two categories of parallel computers
    Multicomputer:
    A parallel computer is constructed out of multiple computers and an interconnection network. (message passing)
    Centralized multiprocessor(symmetric multiprocessor or SMP)//集中式多处理器(对称多处理器或SMP):
    A more highly integrated system in which all CPUs share access to a single global memory. (communication and synchronization by sharing memory)



    来源: Guoming Lu,Chapter1-Introduction.pdf(p16),UESTC

    来源: oreilly,Parallel versus distributed computing,https://www.oreilly.com
    Why Parallel Computing?
    对计算能力的需求
    气候模拟蛋白质折叠药物发现
    摩尔定律变得不太可靠,晶体管密度的增加会伴随着热量的增加,太热了集成电路就变得不可靠了,进而往多核处理器方向发展,并行就显得很重要
    How Do We Write Parallel Programs?
    Task parallelism(任务并行)
    Partition various tasks carried out solving the problem among the cores.

    Data parallelism(数据并行)
    Partition the data used in solving the problem among the cores. Each core carries out similar operations on it’s part of the data.


    eg:
    一次考试,15个问题,一共300个学生参加考试,也就是300份卷子,现在需要进行改卷。有三个人(处理器)进行改卷。

    Task parallelism
    分成3个任务,分别处理Q1-Q5、Q6-Q10、Q11-Q15
    Data parallelism
    每个人改100份


    协调工作coordinationCores usually need to coordinate their work.

    Communication(通信)
    one or more cores send their current partial sums to another core.
    Load balancing(负载平衡)
    share the work evenly among the cores so that one is not heavily loaded.
    Synchronization(同步)
    because each core works at its own pace, make sure cores do not get too far ahead of the rest.

    并行硬件和并行软件冯·诺伊曼瓶颈
    图:冯诺依曼结构 来源:wikipedia

    冯诺依曼结构:是一种将程序指令存储器和数据存储器合并在一起的电脑设计概念结构。
    在这之前每个程序都是直接设计成电路板的,也就是程序和数据是分离的,每需要修改程序就要重新焊一个电路板。冯诺依曼设计的构想是将成也转为编码然后和数据存储到一起。这种设计思想导致了硬件和软件的分离,即硬件设计和程序设计可以分开执行!

    将CPU与存储器分开并非十全十美,反而会导致所谓的冯·诺伊曼瓶颈(von Neumann bottleneck):在CPU与存储器之间的流量(资料传输率)与存储器的容量相比起来相当小,在现代电脑中,流量与CPU的工作效率相比之下非常小,在某些情况下(当CPU需要在巨大的资料上运行一些简单指令时),资料流量就成了整体效率非常严重的限制。CPU将会在资料输入或输出存储器时闲置。由于CPU速度远大于存储器读写速率,因此瓶颈问题越来越严重。
    Refrence: wikipedia-冯诺依曼体系
    目前解决的方案: 多级缓存、分支预测
    对冯诺依曼模型的改进缓存Cache高速缓冲存储器(Cache,简称缓存)
    Cache 映射
    虚拟存储器交换空间

    TLB(Translation-Lookaisde Buffer)
    TLB命中
    TLB缺失
    页面失效(page fault)

    1、Buffer(缓冲区)是系统两端处理速度平衡(从长时间尺度上看)时使用的。它的引入是为了减小短期内突发I/O的影响,起到流量整形的作用。比如生产者——消费者问题,他们产生和消耗资源的速度大体接近,加一个buffer可以抵消掉资源刚产生/消耗时的突然变化。2、Cache(缓存)则是系统两端处理速度不匹配时的一种折衷策略。因为CPU和memory之间的速度差异越来越大,所以人们充分利用数据的局部性(locality)特征,通过使用存储系统分级(memory hierarchy)的策略来减小这种差异带来的影响。3、假定以后存储器访问变得跟CPU做计算一样快,cache就可以消失,但是buffer依然存在。比如从网络上下载东西,瞬时速率可能会有较大变化,但从长期来看却是稳定的,这样就能通过引入一个buffer使得OS接收数据的速率更稳定,进一步减少对磁盘的伤害。4、TLB(Translation Lookaside Buffer,翻译后备缓冲器)名字起错了,其实它是一个cache.

    低层次并行指令级并行
    流水线(Pipelining)
    指的是将功能单元分阶段安排
    多发射(multiple issue)
    指的是然多条指令同时启动

    其实因为有多个复制的功能单元,所以可以将多发射和流水线认为时并行硬件。但是这种并行硬件对程序员时不可见的,锁以这里将他看作为对冯诺依曼模型的改进。

    eg: 举一个关于计算的例子,将$9.8710^4$与$6.5410^4$相加
    图:运算步骤 来源:《An Introdution to Parallel Programming》(p26)
    我们假设每次操作要1ns,那么上图共需7ns
    现在执行下面程序,那么大概需要花费7000ns
    float x[1000],y[1000],z[1000];···for(int i=0;i<1000;i++){ z[i]=x[i]+y[i];}
    方案一:Pipelinling
    使用流水线的方法,虽然运行一次可能看不出来差别,但是数量多了就有差距了。
    图:流水线加法。表格中数字表示操作数的下标 来源:《An Introdution to Parallel Programming》(p27)
    可以看出这里for循环从7000降到了1000,提高了近7倍。

    但是k个阶段不能达到k倍的效果,这里面要烤炉每个阶段的运行时间,会不会在某个阶段阻塞。

    方案二:multiple issue
    这个就是复制相同的功能单元来同时执行程序中的不同的指令。
    假设有两个加法器,那么A计算z[0],B计算z[1],A计算完后,计算z[2]。

    硬件多线程(hardware multithreading)有些程序中有很多部分之间有依赖关系,导致不太容易实现和利用指令级并行。
    比如,斐波拉契数f[i]=f[i-1]+f[i-2],这里每次计算都需要上次的结果,就无法设计流水线了。
    指令级并行是执行细粒度的程序单元的并行。
    线程级并行则是尝试同时执行不同线程了提供并行性。
    硬件多线程为系统提供一种机制可以支持线程级的并行,如果当前执行的任务被阻塞时,系统可以继续器他有用的工作。

    细粒度的多线程,处理器在每条指令执行完后切换线程,从而跳过被阻塞的线程。
    可以避免因为阻塞导致机器时间的浪费缺点:执行很长一段指令的线程在执行每条指令的时候都需要等待。
    粗粒度的多线程,只切换需要等待很长时间才能完成操作而被阻塞的进程。就是这种进程才使用这种每条指令执行完后切换线程机制。
    并行硬件这里说的是如果能够通过修改源代码进而开发并行性或者必须修改源代码来开发并行性,那么认为这种硬件是并行硬件。
    Michael J. Flynn是美国斯坦福大学的计算机教授,1972年他提出了著名的费林分类法(Flynn’s taxonomy,或Flynn’s classifications)。Flynn’s taxonomy是一种经典的计算机体系结构分类方式。Flynn根据指令流、数据流的多倍性特征把计算机系统(或体系结构)分成了四类:

    SISD : single instruction single data
    Execute a single instruction at a time and fetch or store one item of data at a time Model of serial Von Neumann machine Logically, single control processor
    MISD : multiple instruction single data
    Multiple Instruction Single Data The term isn’t used (except when discussing the Flynn taxonomy) . Perhaps applies to pipelined computation.
    SIMD : single instruction multiple data
    Applies the same instruction to multiple data items. A single control unit and multiple ALUs Multiple processors execute the same program in lockstep.
    In a “classical” SIMD system, each ALU must wait for the next instruction to be broadcast before proceeding. All the ALUs execute the same instruction or are idle.
    Parallelism achieved by dividing data among the processors. Data that each processor sees may be different.GPU利用了这方面的知识。
    MIMD : multiple instruction multiple data
    这其实也为并行计算的模型提供了四种实现方式(当前其中SISD其实就是串行的)。
    对于涉及大量并行数据的应用而言,SIMD 架构的机器无疑是性价比最高的选择。在这种机器上,单个的 control unit 会将 instructions 向多个 processing elements 并行地进行广播,其中每个 PE 都是拥有本地存储器的一个功能单元集合。
    现在市场上的多处理系统更多属于 MIMD 架构的,它比 SIMD 更进一步。一些标准的处理器和存储芯片通过高速总线在内部进行连接(memory 通常是交织的)。
    美国计算机科学家、纽约大学教授 Jacob T. Schwartz 定义了两种大致的方法来组织处理器和内存,即 Paracomputers 和 Ultracomputers。Paracomputers 将 memory 从处理中分离出来。Memory 是共享的,处理器之间通过共享的 memory 来进行通讯。在 Paracomputers 中,如果我们认为每一个内存地址都可以被每一个处理器均等地访问,那么就可以据此认为 PRAM 模块以这种方式来被 Paracomputers 近似地模拟。另一方面,Ultracomputers 将 memory 分配给若干个处理器,这样就形成了众多 modules,一个处理器可以用恒定时间来访问它的 module 上的 memory,但是访问远程的 module 上的 memory 则要耗费更长时间。
    在更多的资料中,我们常常用另外两个术语来替代 Paracomputers 和 Ultracomputers,即多处理器共享内存(multiprocessor shared memory)和多计算机分布内存(multicomputer distributed memory),在共享内存系统中,处理器通过对全局皆知的内存地址(globally known memory address)进行读写来实现通信。硬件实现上会确保所有处理器对内存都有用相同的访问方式(即使用单一地址空间)。因此,这也被称为是对称多处理器机 “symmetric multiprocessor (SMP) machine”。而在分布内存系统中,处理器之间通过发送消息的方式来进行通信。此时硬件将仅负责消息的传递。也不再有单一地址空间。所以这也被称为是消息传送机器(message passing machine)。一个分布共享内存 (DSM) 系统拥有一个分布式的内存但是是一个单一的地址空间。 通常在 SMP 机器上编程要比再 message passing machine 上编程容易很多。然而,message passing machine 可以用更低的代价来进行扩容。
    来源:CSDN 白马负金羁
    共享内存系统一个多核处理器在一块芯片上有多个CPU或者核。通常。每个核都拥有是私有的L1cache,而其他的Cache可以在核之间共享,也可以不共享。
    类型有

    一致内存访问(Uniform Memory Access,UMA)
    多个处理器直接连到一块内存上。
    非一致内存访问(Nonuniform Memory Access,NUMA)
    通过处理器中内置特殊的硬件,可以访问其他处理器的内存。

    分布式内存系统最广泛使用的是集群(clusters).
    1 留言 2021-03-22 19:02:46 奖励20点积分
  • 机器视觉MIL Mod匹配

    MIL几何模板查找器模块MIL几何模板查找器模块是一组用于根据几何特征查找图案或模板的功能。该模块使用基于边缘的几何特征而不是像素到像素的相关性来查找模板。这样,与相关模式匹配相比,“模板查找器”模块具有多个优势,包括对照明变化(包括镜面反射)的更大容忍度,模板遮挡以及比例和角度的变化。
    使用“模板查找器”模块可以定制搜索以适合应用程序的需求。您可以通过一系列角度和比例同时搜索任意数量的不同模板。您还可以使用Model Finder搜索不同种类的模板,包括从图像创建的模板(图像类型),从Edge Finder结果缓冲区创建的模板(Edge Finder类型),从Model Finder结果缓冲区创建的模板(Model Finder类型) ,模板是从之前的两个模板(合并类型)和综合模板合并而来的。合成模板可以是具有预定义形状的模板,也可以是从CAD文件定义的模板。
    该模块为校准提供了完整的支持。可以在经过校准的真实世界中进行搜索,从而无需物理校正图像,即使在存在复杂失真的情况下也可以发现出现的情况,并以真实世界为单位计算结果。
    该模块还允许您从文件或内存流中还原Model Finder上下文,或将Model Finder上下文保存到文件或内存流中。
    通常可以使用MedgeInquire()查询所有控件设置。
    为了使新的上下文设置生效,您必须使用MedgeCalculate()计算设置。
    请注意,某些控件设置具有计算后的限制。有关更多信息,请参见第9章:Edge Finder中“计算和检索结果”部分中的“计算后”子部分。
    通过将ControlType参数设置为M_INTERACTIVE,可以交互设置控件类型。
    以下步骤提供了使用MIL几何模板查找器模块的基本方法:

    使用MmodAlloc()分配模板查找器上下文
    使用MmodDefine()或MmodDefineFromFile()定义模板并将其添加到此Model Finder上下文中
    如有必要,请使用MmodMask()掩盖模板中任何不相关,不一致或无特征的区域
    使用对MmodControl()的连续调用,为上下文和单个模板指定所需的搜索设置
    使用MmodPreprocess()预处理Model Finder上下文
    使用MmodAllocResult()分配结果缓冲区以保存搜索结果
    使用MmodFind()在目标中搜索目标中模板的出现情况
    使用MmodGetResult()从结果缓冲区中检索所需的结果
    如有必要,请使用MmodSave()保存您的Model Finder上下文
    使用MmodFree()释放所有分配的对象

    有关使用校准的模板源图像和目标的信息,请参阅本章后面的“校准”部分。
    基本概念“模板查找器”模块的基本概念和词汇约定为:

    活动边缘:用于构成几何模板而不会被掩盖的边缘,并在目标中进行搜索
    边界框:完全包围模板所有边缘的最小矩形
    链:构成边的一组连接的Edgel
    边缘:描绘边界的曲线,可以根据图像中的强度转变来建立边界。在“模板查找器”中,边被视为链及其特征
    Edgel:边缘内的基本点(或边缘元素)
    模板:该信息定义了要在目标中找到的活动边缘的模式以及用于进行搜索的搜索设置
    模板箱:划定模板边界的框。本质上,模板框是边缘加边界的边界框。对于图像类型和Edge Finder类型的模板,在定义模板时会指定模板框的大小。对于合成模板,可以在定义模板后调整边距
    模板查找器上下文:您要查找的所有模板的容器。使用“模板查找器”上下文,可以设置适用于搜索算法的全局搜索设置
    模板图像:对于图像类型和Edge Finder类型的模板,模板图像是模板源图像中已定义模板的区域的副本。请注意,“边缘查找器”类型模板的模板源图像是结果缓冲区的图像源。对于合成模板,模板图像是模板的图像表示(边缘图)
    模板面具:用于定义模板中不相关,不一致或无特征区域的二进制图像,因此仅将相关的模板详细信息用于搜索
    模板原点:模板坐标系中的点被视为(0,0)
    模板源:模板边缘的直接来源。例如,对于Edge Finder类型的模板,模板源是Edge Finder结果的缓冲区
    模板源图像:从中定义图像类型模板或从中提取边缘查找器类型模板的边缘的图像
    发生:在目标中找到的模板的实例
    分数:在事件中发现的模板中活动边缘的度量,由这些公共边缘的位置偏差加权
    综合模板:具有预定义形状(例如圆形或正方形)或从CAD类型的文件定义的模板
    目标:在其中搜索模板出现的图像或结果缓冲区
    目标分数:在事件中发现的原始模板中不存在的边缘的度量,由公共边缘的位置偏差加权
    目标边缘:目标中的边缘
    3 留言 2021-03-21 10:38:13 奖励30点积分
显示 0 到 15 ,共 15 条

热门回复

  • 基于WinPcap实现的UDP发包程序
    如果在vs 编译时出现 无法找到元数据文件 platform.winmd 应该怎么解决
    2021-03-23 09:58:16 thumb_up( 2 )
  • 机器视觉MIL Mod匹配
    You can also search within the full angular range of 360� from the nominal angle specified with M_ANGLE. Use the MmodControl()�M_ANGLE_DELTA_POS and M_ANGLE_DELTA_NEG control types to specify the angular range in the counter-clockwise and clockwise direction from the nominal angle, respectively; the default for both is 180�. The angular range limits the possible angles which can be returned as results for an occurrence. Note that the actual angle of the occurrence does not affect search speed. If you need to search for a model at discrete angles only (for example, at intervals of 90 degrees), it is typically more efficient to define several models with different expected angles, than to search through the full angular range. By default, calculations specific to angular-range search strategies are enabled. If you expect that the occurrences sought are close to the specified nominal angle, you can disable these calculations using MmodControl() with M_SEARCH_ANGLE_RANGE set to M_DISABLE. When disabled, you must specify a good nominal angle for each model, which is within the model's angular range. You can restrict which candidates are returned as occurrences by narrowing the angular-range. Note that M_SEARCH_ANGLE_RANGE must be enabled to search for a rotation-invariant non-synthetic model (for example, an image-type model of a circle).
    2021-03-20 13:27:51 thumb_up( 2 )
  • 基于SSM的超市订单管理系统
    可以用吗,怎么用的
    2021-04-14 15:44:50 thumb_up( 1 )
  • 线程同步之临界区
    程序还算比较简单的,谢谢分享
    2019-04-20 12:24:58 thumb_up( 1 )
eject