界面效果

设置说明: 设置文件在软件目录下的 set.xml

  1.              cuuId 为当前选择的时间同步服务器ID 就是下面第几个item里的配置 (从零开始)

  2.   
          item 时间服务器列表项  
          name 时间服务器名称  
          ip   时间服务器地址 
          ip2  保留
  3.    后台服务时间同步方式 
              type 1 开机就同步 同步成功后停止服务 
                 2 开始服务后每隔STime分钟同步一次 
              STime   间隔的时间
  4.   日志记录方式
               level 2   记录程序运行生成的调试信息和错误信息
                   3    只记录程序运行产生的错误信息
                   4   不记录任何日志

**注 在界面上或者手动修改配置文件后要手动停止服务在启动服务

程序出来缘由: http://caipiao365.vip/article/12

程序源码: https://gitee.com/zuzong/Projects/tree/master/MyTime

程序下载: https://gitee.com/zuzong/Projects/raw/master/MyTime/exe/MyTime.zip

 缘由 

 家里有两台老电脑,有cmos电池没有电了,还有应该是BIOS出问题了.每次开机后时间恢复成了出厂时间.虽然不是什么大问题,但是也给使用时带来了很大的不方便.然后用win的时间同步服务一直更新不成功.折腾了好长时间(不知道为什么),估计是人长的丑的缘故吧^_^,有知道原因的麻烦告诉我.然后在网上找了一些时间同步的工具,发现不是有广告就是要手动去更新时间,然后就想这与其乱费长时间去试一个个的软件,还不如自己花点时间写一个. 就这样[时间同步小助手]就出来. 

事因

先不废话,来张让人看了就上火的图片.因为平时用浏览器用的多.所以开机就喜欢打开chrome.结果出现下面这张可恶的图片.

然后打开服务一看,Windows Time服务是自动启动的 而且正在运行中.就这样我打一下面这个界面.


选择里面的服务器 点立即更新 都没法更新. 在这里自己输入时间服务器,结果也报错.没办法就来野蛮一点的打开注册表转到[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\DateTime\Servers]手动加时间服务器.然后重启在看里面有了但是还是更新出错.然后左百毒右谷歌,从比必到yandex. 搜到了一些大同小异的文章.然后高高兴兴的去按搜到的资料上的去做,结果我这台电脑居然不按套路出牌.

运行 w32tm  unregister

给我的回复是 

发生下列错误: 拒绝访问。 (0x80070005)

运行 w32tm  /debug /enable /file:......

给我的回复是 

发生下列错误: 拒绝访问。 (0x80070005)

反正执行 不管如何执行 w32tm的相关命令就给那一直不变的 友好的提示:发生下列错误: 拒绝访问。 (0x80070005)

 

然后就想着不想在折腾你了.没有那么多时间来折腾.去网上找时间同步的软件.下个一来丢盘即用就可以了.然后把时间更新了一下.打开chrom来搜 windows时间同步工具. 一看结果好多呀.然后又开始一个一个try.try. 结果大部分软件功能不好用,甚至还用不了.但是广告特别多.而且还绑定了好多的垃圾软件和流氓软件.应正了 安装5分钟,清理两小时.结果一个非常适合晒太阳的下午白白乱费了.然后我那暴躁的脾气上来了.想想宁愿去通宵几个晚上也要自己做一个时间同步小工具来用.说干就卷起袖子开干.

分析

打开 bing   搜  rfc ntp  找到这份文档 https://tools.ietf.org/html/rfc958 

慢慢的啃完了他.定义了下面的通讯结构(主要看 Appendix A UDP Header Format )

struct NTPPacket
{
    union
    {
        struct _ControlWord
        {
            unsigned int uLI : 2;          // 00 = no leap, clock ok
            unsigned int uVersion : 3;     // version 3 or version 4
            unsigned int uMode : 3;        // 3 for client, 4 for server, etc.
            unsigned int uStratum : 8;     // 0 is unspecified, 1 for primary reference system,
            // 2 for next level, etc.
            int nPoll : 8;                 // seconds as the nearest power of 2
            int nPrecision : 8;            // seconds to the nearest power of 2
        };

        int nControlWord;                  // 4
    };

    int nRootDelay;                       // 4
    int nRootDispersion;                  // 4
    int nReferenceIdentifier;             // 4

    __int64 n64ReferenceTimestamp;        // 8
    __int64 n64OriginateTimestamp;        // 8
    __int64 n64ReceiveTimestamp;          // 8

    int nTransmitTimestampSeconds;       // 4
    int nTransmitTimestampFractions;     // 4
};

/*
主要字段的解释如下:

l              LI(Leap Indicator):长度为2比特,值为“11”时表示告警状态,时钟未被同步。为其他值时NTP本身不做处理。

l              VN(Version Number):长度为3比特,表示NTP的版本号,目前的最新版本为3。

l              Mode:长度为3比特,表示NTP的工作模式。不同的值所表示的含义分别是:0未定义、1表示主动对等体模式、2表示被动对等体模式、3表示客户模式、4表示服务器模式、5表示广播模式或组播模式、6表示此报文为NTP控制报文、7预留给内部使用。

l              Stratum:系统时钟的层数,取值范围为1~16,它定义了时钟的准确度。层数为1的时钟准确度最高,准确度从1到16依次递减,层数为16的时钟处于未同步状态,不能作为参考时钟。

l              Poll:轮询时间,即两个连续NTP报文之间的时间间隔。

l              Precision:系统时钟的精度。

l              Root Delay:本地到主参考时钟源的往返时间。

l              Root Dispersion:系统时钟相对于主参考时钟的最大误差。

l              Reference Identifier:参考时钟源的标识。

l              Reference Timestamp:系统时钟最后一次被设定或更新的时间。

l              Originate Timestamp:NTP请求报文离开发送端时发送端的本地时间。

l              Receive Timestamp:NTP请求报文到达接收端时接收端的本地时间。

l              Transmit Timestamp:应答报文离开应答者时应答者的本地时间。

l              Authenticator:验证信息。

*/

 

核心代码

UDP通信的代码如下:

#define JAN_1970        0x83aa7e80 /* 1900年~1970年之间的时间秒数 */

bool TimeSockService::GetNetTime(const string strIP,UINT64 &uRetTime)
{
    SOCKET SendSocket;  
    sockaddr_in RecvAddr;  
    uRetTime = 0;
    UString strError; 
    SendSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); 
    RecvAddr.sin_family = AF_INET;  
    RecvAddr.sin_port = htons(123);  
    HOSTENT* pHostent = gethostbyname(strIP.c_str());  
    if (pHostent != NULL)
    {  
        RecvAddr.sin_addr.s_addr = *(u_long *)pHostent->h_addr_list[0];;  
    }else 
    {
        strError.Format(L"error in gethostbyname: %d \r\n%s", WSAGetLastError(), sysErrorMsg().c_str());
        LOG_ERR(strError.GetData());
        if (_hWndGUI) SendMessage(_hWndGUI, WM_GET_NET_TIME_ERR, 0, LPARAM(strError.GetData()));

        return false;  
    }

 
    NTPPacket ntpSend = { 0 };
    ntpSend.nControlWord = 0x1B;  
    NTPPacket ntpRecv;

    int tv_out = 5000; 
    setsockopt(SendSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv_out, sizeof(tv_out));
    sendto(SendSocket, (char*)&ntpSend, sizeof(ntpSend), 0, (SOCKADDR *)&RecvAddr, sizeof(RecvAddr));  

    sockaddr fromAddr = { 0 };  
    int nRead = sizeof(fromAddr);  
    if (SOCKET_ERROR != recvfrom(SendSocket, (char*)&ntpRecv, sizeof(ntpRecv), 0, &fromAddr, &nRead))  
    { 
        uRetTime = ntohl(ntpRecv.nTransmitTimestampSeconds) - JAN_1970; 
    }else
    {  
        strError.Format(L"error in recvfrom: %d \r\n%s", WSAGetLastError(), sysErrorMsg().c_str());
        LOG_ERR(strError.GetData());
        if (_hWndGUI) SendMessage(_hWndGUI, WM_GET_NET_TIME_ERR, 0, LPARAM(strError.GetData()));
    }
    closesocket(SendSocket);
    return true;
}

结果

然后封装成win的服务程序.为了方便管理做了个界面.具体效果如下:

验证结果

设置成开机同步后运行后看的效果:

具体用法请点界面上的说明 按钮.欢迎使用找BUG.有什么问题欢迎在这里砸砖头^_^

程序下载地址: https://gitee.com/zuzong/Projects/raw/master/MyTime/exe/MyTime.zip

个人博客地址:http://caipiao365.vip/article/12

更多帮助: http://caipiao365.vip/article/MyTime

习惯了linux的命令 然后在win下时不时的 输上了ls   clear 结果返回错误。然后自己又不想安装一在对的其他的环境。然后记得win下有一条命令是 doskey。可以给现有的命令取个别名。这个的话就方便多了

写一个小脚本 如下 保存成 doskey.cmd

@echo off
@doskey clear=cls $*
@doskey top=tasklist $*
@doskey ls=dir $*
@doskey mv=move $*
@doskey cp=copy $*
@doskey cat=type $*
@doskey pwd=echo %cd%
@doskey grep=findstr $*
@doskey ifconfig=ipconfig $*

要是还有其他的命令可以自己加



然后打开注册表

找到 HKEY_CURRENT_USER\Software\Microsoft\Command Processor这里

在这里下面 建立一个 名叫 AutoRun的字符串 值为上面脚本保存的路径,如下图


保存后在打开cmd就可以看效果了



希望对大家有用



刚刚从服务器上备份了一下数据库然后要到本机调试一些东西,结果点导入时给我提示出错了.

然后二话不说去看了下文件编码, 一看是UTF-8的想应该是没有BOM的原因,然后二话不说打开notepad++ 给他加上BOM标示.


结果提示文件太大.在试了一下vscode也提示文件太大.然后就不想试期他的了.要想一下如何给这个大文件加上BOM标示呢. 脑壳疼脑壳疼.疼了一下就想灵光一现.


开始装B了.

  1. 打开notepad++(其他的编辑器也可以) 建立一下文本文件 输入 --(因为--是sql的注释字符) 然后保存成带BOM的文件 我给他取名为 bom.sql,如下图片

  2.  然后打开CMD执行下面的命令

    copy bom.sql+bak.sql  1.sql


在把1.sql导入到DB里面


装B成功



上面只供参考,要是个位还有其他的好方法麻烦告诉我^_^



摘要: 曾经在工作当时招的各种各样的程序员。也带过各种各样的人。然后在带人的过程中发现了一些短板,所以就准备写几片程序设计之学前班的基础文章来。暂时先上一篇看看效果。要是觉得好麻烦告诉你的身边的人或者好友。要是觉得不好麻烦您一定要告诉我。

前言

在我们的日常生活用语里经常用的就一个词就是半斤八两,首先我介绍一下半斤为什么是八两.在中国以前重量的单位的16进制的,就是16两等于一斤,当然在香港还是保持着司马量的习惯.(台湾没有去过不知道).后来建国后为了和国际接轨才改成了十两一斤.当然这里不是给大家普及一这个小知识.这里要注意的是  16两为一斤.就是缝16进一.也就是16进制.看看中国是最早使用16进制的国家吧.当然不单单是16进制.为会标题说堂堂5尺爷们不到100斤呢,这里不是在吸引眼球瞎说,尺是长度单位,1米大概是3.3333尺,算一下5尺就是1.666米左右,一个1.6米左右的爷们不到160斤那纯粹是个标准身材.要是超过了那么就是太有安全感了.

数字的进制

刚刚说了16进制是逢16进一的,还有逢二进一二进制, 逢8进一的8进制, 逢12进一的12进制如时间. 逢60进一时时间的分秒等,这些在我们生活当中经常使用的.而且用了好多好多年了.

二进制

如你家开饭的时候你要去摆碗筷.如人5个人你就要拿5双筷子,而不是说要10只筷子.看看我们的老祖宗是最早使用二进制的.而且把还做了几次运算先转换成二进制,在转换成十进制.

二进制数只有0和1两个基本数字,由于大家都知道直流电只有正负两个电极所以在电器设备里(我说的是数字电器设备) 容易在电气元件中实现,所以用二进制表示非常方便,

二进制数的运算

二进制数的运算公式:

0+0=0 0×0=0

0+1=1 0×1=0

1+0=1 1×0=0

1+1=10 1×1=1

八进制

八进制也是我们国家用的最早的.我一说大家就想到了是八卦,对就是八卦,但是八卦不单单是八进制,他是八进制和二进制结合的产物.在这里不去详细讲解.这个只做了解就可以了,具体原因后面在讲.

十六进制

这个刚刚在前言里讲了不在详细讲解了. 16进制要16个字符来表示.其中 0到9表前前10个字符, 然后用字符ABCEDF这几个字符来表示 11 12 13 14 15.在计算机为了表示数据就用了16进制,这个非常好理解.如你家要是有100个有吃饭,你要准备多少个碗,多少双筷子时不是说的是 100个碗 100双筷子了,大部分说的是 要准备13(我说的是八仙桌,就是八人一桌的)桌的餐具了.看看日常生活当中又用到了8进制和二进制,而且是个正常人就会听明白.为会要说13桌不说100个碗和100双(或200根)筷子呢.主要是方便自己说的文字少了.别人一听就明白.所以计算机为了显示一些数据用的是16进制的方式去显示.如果用二进制去显示那么显示的文字就非常多一大堆的0和1不方便.

不同进制的转换

接着上面的说100个人要准备13着的问题,在这个100人变13桌的过程中您已经把10进制转换成了8进制然后在转换成了10进制,几乎是不假思索的.但是计算机就比你笨了好几个次方倍了,应为他不会转换.他的转换是人告诉的.现在来看看外国的那些猴子是怎么教计算机来转换不同的进制的

1.  十进制和二进制间的转换

将十进制整数转换成二进制整数时,只要将它一次一次地被2除,得到的余数从最后一个余数读起)就是二进制表示的数。

2.   二进制数转换成十进制数

将一个二进制数的整数转换成十进制数,只要将按权展开。

例:11011=1*24(2的4次方)+1*23(2的3次方)+0*22(2的2次方)+1*21(2的1次方)+1*20(2的0次方)=27

3. 不同进制数的转换

二进制数和八进制数互换:二进制数转换成八进制数时,只要从小数点位置开始,向左或向右每三位二进制划分为一组(不足三位时可补0),然后写出每一组二进制数所对应的八进制数码即可。

例:将二进制数(10110001.111)转换成八进制数:

010 110 001. 111

2 6 1 7

即二进制数(10110001.111)转换成八进制数是(261.7)。反过来,将每位八进制数分别用三位二进制数表示,就可完成八进制数和二进制数的转换。

二进制数和十六进制数互换:二进制数转换成十六进制数时,只要从小数点位置开始,向左或向右每四位二进制划分为一组(不足四位时可补0),然后写出每一组二进制数所对应的十六进制数码即可。

例:将二进制数(11011100110.1101)转换成十六进制数:

0110 1110 0110. 1101

6 E 6 D

即二进制数(11011100110.1101)转换成十六进制数是(6E6.D)。反过来,将每位十六进制数分别用三位二进制数表示,就可完成十六进制数和二进制数的转换。

八进制数、十六进制数和十进制数的转换:这三者转换时,可把二进制数作为媒介,先把代转换的数转换成二进制数,然后将二进制数转换成要求转换的数制形式。

 

数据的编码----之MS的崛起

也许你听过MS,或者没有听过MS,但是或多或少你都用过MS的东西.如他的操作系统windows,他的办公软件 office他的浏览器IE等,但是你也许不知道MS这艘航母是怎么从当时的地下车库一步一步的搬进他现在的大厦的.

先我来啰嗦一下,说说前面的8进制,本来是我们的老祖宗玩的非常溜的,但是由于这个8进制在曾经很长的一段时间内制约了中国的计算机发展,乃至于全球的(个人是这样认为的).为什么呢?现在我来慢慢和你道来:

大家都知道,我们的电脑全的全称叫电子数字试计算机.看看电子数字试这几个子,电子我们初中的物理老师和化学老师讲了只有正极和负极.那么数字试是什么意思想,正极和负极可以表示多少个数字呢?好吧我也不知道,高中数学课上开小差了.那我们现在来一个非常完美的假设

有两个电极如下(用0表示- 用1表示+)

电极A

电极B

结果

0

0

第一种情况

0

1

第二种情况

1

0

第三种情况

1

1

第四种情况

聪明的您肯定一下就算出来了 2*2=4种情况了.是的没有错就是两个位可以表示的信息非常有限就只能表示4种信息.当然计算机是国外的科学家发明的.他们可能都不会中文,因为他们用的是英文说的是英语.我们看看因为是26个字母.包括大小些才52个 在加上一0到9十个常用的数字.才62个,想想还有一写标点符号,有多少个初中的英语老师没有告诉我,我就假设一下吧,算30个吧应该差不多了吧.这样的话62+30才90多个不到100个.数学好的你肯定就知道了,要多少个位就可以表示完这100来个的信息了.对7个位就可以表示完了.7位组合下来可以表示128个信息.但是中国有句老话叫孤阴不生,独阳不长.这话的什么意思呢.自己去google里百度.我只知道让你去提水,你肯定提2的倍数是最优的,因为不是二的倍数的话有一次是单的.电器设备里的电极也是成双成对出现的,计算机里的最基本的单位是bit(位),但是美国的那些科学家们只考虑了他的使用环境,就把计算机的的一个字节定义成了8个位.为什么是8个呢.因为表示他们的单词和数字以及标点符号等这些有7个位足够了.所以他们就定义出来了一个字节8个位.

1个字节=8个位

1k=1024个字节

1M=1024K

1G=1024M

1T=1024G

美国信息交换标准代码

据说long long a go. 电脑不像现在的这样(废话). 现在我可以在我电脑上编辑好一份文件然后发给你,你就可以在你的电脑上打开看了甚至编辑了.要是在很久以前的,那些用电脑的人看到了就会觉得非常非常神奇.应为以前的电脑在a电脑上编辑的文件只能在a电脑上看.不能在b电脑上看.两边电脑的系统信息编码不一样.然后MS就出来.比尔该死借助他妈是IBM销售部的部长.他就写了一套软件系统.基本上和当时市面上用的功能是一模一样的,但是他比其他的dos多了一个功能.就是在任何一台安装有MS_DOS的IBM兼容机上编辑的文件可以在其他任何一台安装MS_DOS的IBM兼容机上打开并且编辑.这样使得他的系统大买,也让IBM的PC机也大买.后来你懂得了,有钱,有个好妈妈.抱上了巨人(还是国际巨人)的大腿.很会做销售和市场(废话,当妈就是销售精英),还懂技术的人.想不挣钱都难.所以他就二话不说.从学校和老师说了句我妈妈叫我回家数钱去.就辍学了.

 

美国标准信息交换代码是由美国国家标准学会(American National Standard Institute , ANSI )制定的,标准的单字节字符编码方案,用于基于文本的数据。起始于50年代后期,在1967年定案。它最初是美国国家标准,供不同计算机在相互通信时用作共同遵守的西文字符编码标准,它已被国际标准化组织(International Organization for Standardization, ISO)定为国际标准,称为ISO 646标准。适用于所有拉丁文字字母。 

标准表

(图片来源百度百科)

 

 

 

汉字编码

在计算机中一个汉字通常用两个字节的编码表示,我国制定了“中华人民共和国国家标准信息交换汉字编码字符集(基本集GB2312—1980)”,简称国标码,是计算机进行汉字信息处理和汉字信息交换的标准编码。在该编码中,共收录汉字和图形符号7445个,其中一级常用汉字3755个(按汉语拼音字母顺序排列),二级常用汉字3008个(按部首顺序排列),图形符号682个。

在GB2312—1980中规定,全部国标汉字及符号组成一个94×94的矩阵。在此矩阵中,每一行称为一个“区”,每一列称为一个“位”。于是构成了一个有94个区(01~94区),每个区有94个位(01~94位)的汉字字符集。区码与位码组合在一起就形成了“区位码”,唯一地确定某一汉字或符号。

区位码的分布规则如下:

1)01~09区:图形符号区。

2)10~15区:自定义符号区。

3)16~55区:一级汉字区,按汉字拼音排序,同音字按笔画顺序。

4)56~87区:二级汉字区,按偏旁部首、笔画排序。

5)88~94区:自定义汉字区。

(2)汉字输入码

所谓汉字输入码就是用于使用西文键盘输入汉字的编码。每个汉字对应一组由键盘符号组成的编码,不同的汉字输入法其输入码不同。汉字输入码也称外码。常见的汉字输入编码方案可分为如下4类:

1)数码:用数字组成的等长编码,典型代表有区位码、电报码。

2)音码:根据汉字的读音组成的编码,典型代表有全拼码和双拼码。

3)形码:根据汉字的形状、结构特征组成的编码,典型代表有五笔字型、表形码。

4)音形码:将汉字读音与其结构特征综合考虑的编码,典型代表有自然码、首尾拼音码。

(3)汉字内码

无论用户用哪种输入法,汉字输入到计算机后都转换成汉字内码进行存储,以方便机内的汉字处理。汉字内码是采用双字节的变形国标码,在每个字节的低7位与国标码相同,每个字节的最高位为1,以与ASCII码字符编码区别。

(4)汉字字形码

汉字字形码(汉字输出码)是将点阵组成的汉字模型数字化,形成一串二进制数称为汉字字形码,其主要用于输出汉字。输出汉字时,将汉字字形码再还原为由点阵构成的汉字,所以汉字字形码又被称为汉字输出码。

汉字是一种象形文字,每一个汉字可以看成是一个特定的图形,这种图形可以用点阵、 轮廓向量、骨架向量等多种方法表示,而最基本的是用点阵表示。如果用16x16点阵来表示 一个汉字,则一个汉字占16行,每一行有16个点,其中每一个点用一个二进制位表示,值“0” 表示暗,值“1”表示亮。由于计算机存储器的每个字节有8个二进制位,因此,16个点要用 两个字节来存放,16x16点阵的一个汉字字形需要用32个字节来存放,这32个字节中的信息 就构成了一个16x16点阵汉字的字模

Unicode

Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。1990年开始研发,1994年正式公布。

 




注意:本文属于原创。首发于自己的博客: http://caipiao365.vip/article/25

欢迎转载,转载请保留上面的链接谢谢合作。版权保留。


世界上最早的计算机

起源

在小时候叼毛我给家人逼着去背当时自己不明白的口诀,什么 一上一,二上二,三上五除二……(有兴趣的朋友自己去google里百度 算盘 606口诀). 现在想想当时背的是一套多么高深又简单的数学模型和算法. 这个模型和算法经历了2600多年的历练和优化,而且现在还在用.(自己去小城市的一些店铺里看看是不是还有很多的掌柜也可能是老板用的是这个神器).所以历史在一次向我们证明,经得起人们折腾的东西才是好玩意。我个人相信这东西还会继续延续下去。因为这东西了维护成本几乎忽略不计的,二期可用性非常强,对使用者的要求不高。不需要太多太多的专业知识,最重要的就是这神器遇强则强遇弱则弱(其实我们老祖宗给我们留下的很多宝贝这样的),不像大家见到的电子计算器这些电子产品,有寿命还有维护成本。所以这是多么难得的可贵的而且伟大的神器.让我们来看看这个神器的真正面目:

   

别问我为什么用两张图片,我只想告诉您.在这2600多年中不管是平民百姓还是商业大咖.都在用这个神器.顺便告诉大家一个大秘密.这件神器让各位过上幸福的生活和不可磨灭的贡献.因为我国的原子弹就是靠几屋子人用算盘的算出来的.当然在中国古代非常多的著名的建筑在动工前的计算也离不开这神器。


国际巨人----IBM的崛起之初

上面讲了我国最早的计算机现在我们来看看在机械革命后外国人发明的计算机,说到计算机我不得不说到IBM的创始人赫尔曼·霍尔瑞斯教授,他于1888年发明自动制表机——首个使用打孔卡技术的数据处理机器。自动制表机用于1890年以及后续的美国人口普查,并获得巨大成功(发现没有,不单是在国内是政府的钱好挣,国外也是,看看IBM和oracle的崛起就知道了)

 

看看是不是和我们的算盘非常像呀.加上机械的概念让人家一下就觉得高大上.其实就是盗版了我们的算盘.第一张图片就是把我们的算盘立起来.这是把算珠换成了纸(外国人也懒.本来是非常简单通用的东西就硬生生的搞成了复杂不通用的东西,可能是人家没有背上面的口决吧)


然后我们在看看第一台所谓的电子数字试计算机

 

图片看看就可以了,我只会告诉你,现在你用的手机比他要强NNN倍.但是这台电脑最早用的输入设备就是打孔机,就是在纸片上打孔(想想和你在算盘上拨盘珠是一个道理.没有什么高深的,而且打孔非常非常简单.比在算盘上拨盘珠要简单好多倍这就是我说上面这些废话的原因了).

Debug的由来

顺便说一下debug的由来.就是当年有一女神 葛丽丝·霍波(Grace Hopper),辛辛苦苦把打好孔的一叠纸张塞入马克2号(Harvard Mark II)中去,然后嘴上说:天灵灵,地灵灵,这台电脑听我令.给老娘运行起来. 结果估计这妞平时欺负多了这台电脑.电脑就是不听话.这样一下这女神就不干了. 卷起袖子就马上就成了女汉子,就开始拆电脑了. 拆开继电器后,发现有只飞蛾被夹扁在触点中间,从而“卡”住了机器的运行。于是,霍波女神诙谐的把程序故障统称为“臭虫(BUG)”,把排除程序故障叫DEBUG,后来这个就非常优良的延续下来了,成了计算机领域的专业行话。


计算机的发展

其实任何事务的发展都是向两个方向发展的,通用性(说白了就是平民化大家都可以用的),专用的(说白了就是定制的贵的 土豪用的).计算机也是,如PC就是个人电脑的英文缩写.就是通用的, 还就是巨型机,服务器这些就是专用的.具体我就不多介绍了.因为介绍了也没有用,能接触到的不用我介绍,不能接触到的我介绍也没有用.但是这些计算机有一个同用的特点那就是他们都遵循了 冯·诺依曼结构

冯·诺依曼结构

什么是冯·诺依曼结构呢?先我们在回到我们刚刚的算盘上来.看看你要算个数你会在算盘上去拨动一个算珠. 对就是这个算珠.别小看这个玩意.这个东西可以充分的体现我们老祖宗的智慧.为什么呢.我们来分析一下.如你要算一个数.如 123456*56789 正常情况下你会首先听到或者看到 123456 这个数 你可以记到本子上 然后看到 乘号 在记到本子上 在看到56789 在记到本子上这样子的话你的本上就如下

然后在通过您那聪明的 大脑来高速的算出来结果通过笔写到本子上或者通过嘴说出来 .

看看你算这个的时候 你用了些什么呢  通过眼睛去看(或者通过耳朵去听)题目 (输入),然后借助本子去记题目(存储).在运用您那聪明大脑去算 (运算) 这个题目,最后过笔把结果写到本子上(输出).要是你高兴的话你可以用嘴大声的读出来 (输出) ,这些步骤都是在你聪明的大脑的指挥下有条不紊的进行的(控制器).当然你要是想恶作剧使坏的你也可以故意写(说)一个错误的结果(控制器),这主要是一个正常人算一个数学题目的基本过程(非常人的那些看一眼就知道结果的牲口我就不讨论了)

好在回到前面我们说到的算盘,你要算一个数先是在算盘上把珠子调整到这个数.然后在听下一个数在去通过你的手指在上面飞舞很快就可以算出结果了(注意这是不用你的大脑算的)

看看这里可以让你省下了笔 纸 还有就是你的聪明的大脑也可以少死一点细胞.完全就是算盘上的珠子的功劳.这充分体现我们老祖宗的聪明才智了.把输入,输出,运算,存储完美的结合在一起了,只要你的手来充分的控制它.就可以了.

但是外国人可能没有用过我们的算盘.所以他们体验不到我们中国算盘的强大之处.只有通过自己的算数的基本步骤来设计一台电脑.根据上面我们分析的计算一个数的步骤和要用到的一些东西然后再抽象成了一台计算机要下面5个基本的组成部分.

主机,显示器,键盘,鼠标,音箱(嘘,你们小声点,我的计算机入门老师拿着斧头正在赶来的路上,因为我正在误导人家子弟)开心一下,我来个正经一点的:

一台计算机包括以下5大部分

输入设备   如 键盘 鼠标 U盘  手机 等

输出设备   显示器, 打印机  U盘 手机 等

存储设备   内存条  硬盘 U盘 光盘 键盘 算盘等 后面两个不是

运算设备   CPU中的一部分由于外国猴子没有发育完全什么也照搬人类的大脑所以你懂得

控制设备   CPU 中的另一部分 

根据上面我们算数的过程然后抽象了一下计算机的工作流程如下:

 

输入输出设备没有什么讲的了因为我们在日常生活过使用电脑的过程中经常接触过.有些设备你们比我还熟悉.特别是某些人键盘上的某些按键 譬如说 QWER这些键可能磨的字母都看不清了.所就现在我们来讲讲其他的设备

存储设备

要是真心想学的朋友可能在认真的听我在这里一本正经胡说八道,在记东西,要是记性和我一样的兄弟(进入中年,记忆力衰退)可以拿着本记着我说的某些废话.好了现在出来了两个不同的东西是.一种是记到大脑里(或者是心里,具体这两个有什么区别自己去体会),还有一种是记到本子上.麻烦大家想想这两种有什么区别吗?

对了,一般正常人(我们只讨论正常人,非正常的牲口我们不讨论以后也是)记在大脑里的有些东西可能过段时间就忘记了,甚至一转身就忘记了.但是记到本子上的东西,正常情况下会一直在.(当然你的本子丢了,给老鼠咬破了不算),这样的话计算机的存储根据我们人类的这些情况可以抽象成内存(不管是你记在心里还是大脑里)和外存(你记到本子上的)

内存

上面讲到了计算机的内存,只是没有详细说到有些事记到心里和大脑里的区别,现在我们来讲个记到心里和大脑里区别.记得曾经一个非常非常好的朋友,在外面辛辛苦苦打了一年的工(我那个朋友高中毕业就出去工作了).结果高高兴兴回家过年.到我们县城非常非常晚了.大半夜.想想回家了.非常开心.结果出事了.辛辛苦苦一年挣的钱给县城的几个骗子骗了个精光.这件事情他记到了心里.终生难忘.

下面我在说另一件事,我去找一个朋友借钱,说好的多少钱去找他拿钱,结果到时间了他居然说昨天还记得的,结果今天早上一忙就忘记了.

看看人记在心里或者大脑里的也有区别.有的是终身难忘的,有的是过段时间就会忘记了.计算机系统的也是这样的.所以计算机的内存又可以分为 只读存储(爱过痛过刻苦铭心的),还有就是随机存储(爱过累过后的断片)

ROM

爱过痛过刻苦铭心的,就是终生不会忘记的.就会停电了,你把主板砸了,里面的信息还在的.这样的存储叫只读存储.电脑主板上有个叫BIOS的东西就是这个鸟玩意. BIOS 就是最基本的输入输出设备的意思,你开机时说 众神归位 听我号令 然后在按一个特殊的键就可以进入到这个神秘的地主去.


RAM

重要有些事你可能当时记的过段时间就忘记了。在计算机里抽象成了随机存储。随机存储也就是内存里的东西可以读取,也可以写入。但是在计算机断电后里面的所有的信息都会丢失。和你记在大脑里的事情过段时间忘得一干二净差多是一个意思。

好了现在让我们来看看内存长的是个什么样子,至少让我们认识认识他吧。不然以后看到不认识就不要说听过我的课。   


内存和变量的关系

现在我们把内存来看成是一个你做笔记的本子的话,那么你把你的本子在做了点点提高效率的事情就是加上目录,那么以后你要在本子里找一点你需要找的信息就不需要从第一页开始找了,只有从前面的目录(索引)去找了。如你要用的数据在第5页,那么你就直接翻开第5页就找到相关的数据了。但是现实中你在电脑上要处里的数据可能一页放不完,要放好几页,甚至是几十上百页那么你能完全非常清楚的记的那个数据在哪一页吗?要是一般的普通正常人可能很少有这样的能力。那么肿么办呢?对,就是给这内存区域取名,也就是变量名。你去设置变量的值就是把这个变量内存区域的值设置的相应的数据,你获取这个变量的值也就是读取这块内存区域的数据(值)。

函数(方法)和变量名为什么不能以数字和特殊字符开头

在很多的语言当中函数的名称或者方法名称和变量名称不能以特殊字符或数字开头,知道为什么吗?好吧。其实不为啥。就是因为这做这些编译器的人非常非常懒,不想去实现这个功能。因为要实现这个功能工作量非常大。为什么呢。因为前面的课程当中我们讲了计算机是非常非常笨的一种机器。如下面几个符号

1+2   3f   5*5   6&2   4(7f*0)*a *4  !1  =6

在计算机里电脑是非常难判断那个是算术表达试,那个是无意义的字符,所以那些程序编译器或者解释器的开发大牛们就遵循了一个通用的标准,以特殊字符或者数字开头的都以算术表达式的方式去处理。所以就函数的名称或者方法名称和变量名称不能以特殊字符或数字开头,你要是想知道更多的话推荐去看《编译原理》。

外存

上面说上课能有些兄弟会拿笔记到本子上,本子就是外存设备。当然你要是用铅笔写,那么就算本子写满了你也可以用橡皮擦擦掉再继续写,这样的就是你可以读去以前写的笔记,也可以擦除以前的部分笔记再继续写。而且在你的大脑忘记了或者断片后还可以拿这个笔记本来看看,就是说外存断电后里面的信息(数据)是不会丢失的。常用的外存有 硬盘 u盘等。

硬盘

硬盘的尺寸有3.5(台式机用的)的和2.5(笔记本用的,当然台式机或者小主机都可以用的)更多硬盘资料请看这片文章http://caipiao365.vip/article/15(个人电脑数据的安全防护之------<硬盘的日常保养)

现在来两张硬盘的玉照给大家瞧瞧 机械硬盘(3.5,2.5的),和固态(SSD)硬盘。

         

上次一个朋友给我发了上面这张图片。问我说他的硬盘是300G这右下脚的550是什么意思,我告诉他是两个250再加两个 250*0.1的意思。当然是开玩笑的了。这不是550是SSD


运算器

我们在来谈一下我们人类来做数学运算的过程。因为世界上所有的事情都有非常多简单的事情组成的,数学运算也是这样。各种数学运算最终都会抽丝剥茧变成加法和减法。因为加减是其他运算的基础。不管是算卫星的运行轨迹还是导弹的运行轨迹,最终都要用到基础的加减法。好了废话不多说了,如我说要你算一下(5*6)+12等于多少,你会马上告诉我答案,但是你算的太快了。我们放慢速度来分析一下,先你听到5你就会在你大脑里暂时记一下5,在听到乘6,你会把刚刚在大脑里记的5提出来乘以6 并且算出等于30,再暂时记住他,在听到加12,你就又在你的大脑里把刚刚的30提出来,并且算出加12等于多少,再暂时存在你的大脑里。好了,沿用我前面一惯的做法我们来抽象一下我们的过程。

一个运算器要包含的小部件有 

寄存器 用来暂时存运算数据的地方 可细分为:状态寄存器、通用寄存器

运算单元 基本功能为加、减、乘、除四则运算,与、或、非、异或等逻辑操作,以及移位、求补等操作

为了方便理解我们来一张图片来看看计算机是如何傻乎乎的做运算的(为了简单我们来一个逻辑运算吧,而且在程序中也非常用)

先来介绍一下逻辑运算有要有 非、 与、或这三个组成,听字面上的意思大家就知道了。

非 就是相反的意思。如:非零值那就是就这个值不是零

与 就是 A和B两个都要存在

或 就是两个只要一个存在就可以了

先来几个例子如: 我要找你借钱, 

要是你不想借 你可能会说没门 就是非操作。

要是你答应了还要问你爱人,你和爱人都答应了 那就是与操作

要是你或者你爱人两个当中一个人答应了那就是或操作


为了揭开CPU里面的运算器的神秘面纱我们来看看逻辑运算器的简单电路图片

 

当然要是你想了解更多的话请学习:《电子技术》,《数电模电》,《微机电路》这些基础课程了。先要知道二极管PN结是什么鸟玩意,NPN和PNP等等(电子是一门物理和化学结合的课程,看看多学些(或者了解)非本专业的知识是多么的重要。)(又一个非的使用哦,我们生活当中到处在使用逻辑运算)


控制器

控制器这个东西就更好的解释了,他就是一台计算机的总司令,由他去管理什么时候去读取数据,什么时候去做运算,做什么运算等等。



CPU


闲话之电脑升级

运算器和控制中通常都是做到一块芯片里我们叫CPU。早期的CPU是焊死的主板上的(当然现在也有些电脑如工程机,或者是小主机 也是焊死在主板上的)后来由于硬件的更新速度快就没有焊死了,为了方便你升级,所以主板上的各种接口非常多。(顺便也说一下以前大家去配电脑不要相信那些JS说的用什么什么东西,以后升级方便。因为一台电脑用了两三年或者更长时间后你如果想升级的话还不如换一台新的。为什么呢,你想要升级内存发现不是接口不一样的就是速度不一样,安装上了可能会把电脑搞蓝屏。还不如不升级。你想升级显卡以前是VGA的接口,结果一升级是发现是DP的接口然后你还要去换显示器。所以一般说要升级的硬件的时候我个人建议大家去配一台新的电脑还省事)。

  

好了现在我来说说CPU,先看看前面的图片,有针脚是不是呀。放心那是以前的CPU,现在的新CPU没有针脚了。为什么呢?这就要从很久很久以前说起了。话说一个哥们晚上加班很晚而且当时还给工头T了一顿(不要问我为什么用T,因为是搞挨踢的),下班后想想自己多么的苦逼呀,天天没日没夜的加班,越想越觉得自己好苦。然后就去喝闷酒,喝的醉熏熏的回家,回到给他老婆问这问那,讲政治课,结果那哥们的小脾气,一言不合就*****。后来据说他老婆的娘家来人了。恰巧他在修电脑,把主板、cup等都拆下来了。然后他老婆的娘家人和他非常愉快的讲了很多的人生大道理,不过为了让他加深理解和印象让他跪在地上双手楸着耳朵听完的。然后他老婆为了让他在长点记性就把他身边刚刚拆的那块CPU放到了他膝盖下。我那可怜的哥们最后一把鼻涕一把泪向全球男人狗保护协会请求帮助。结果全球男人狗保护协会很快就接到并且处理也他的事情,就有了第二张图片和的CPU。  

其实真正的原因是针脚的CPU在安装和拆的时候容易造成针脚倾斜弯曲和断掉,从而造成整个CPU的报废。

上面的故事纯属虚构,如有雷同实属巧合。

 

单片机

上面我给大家看了CPU的图片 内存的图片 还有硬盘的图片。所以说PC就是一个多片机。说这里的时候,聪明的您就想到了要是我把这些东西集成到一块或者两块型芯里那就是不是叫单片机呢?对了,聪明的您一猜就准。

单片机(Microcontrollers)是一种集成电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU、随机存储器RAM、只读存储器ROM、多种I/O口和中断系统、定时器/计数器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的微型计算机系统。单片机也是电脑,和我们的生活息息相关。如你家的电冰箱,洗衣机,路由器,你天天用的手机等等非常多。好多单片机里的系统和里面的应用是C写的,但是还有好多的单片机里的软件可以支持用python来做。比如说你手机( 你可以搜 在应用市场上搜python),你家的路由器,你可以刷成dd-wrt或者open-wrt.就可以支持python了。看看单片机也没有非常复杂。因为单片机本来就比PC要简单的多。



注意:本文属于原创。首发于自己的博客: http://caipiao365.vip/article/24 

欢迎转载,转载请保留上面的链接谢谢合作。版权保留。



缘起

本人由于胃不太好,从17年11月份离职一直在家里养病.由于父母在家里养了些猪.所以有时,可能自己在房间用电脑做点东西.忽然要去猪圈里干话.一忙就是一上午或者一下午,结果忘记关电脑了.不是心疼电的问题,而是家里猪圈由于多年了,一些电路或者插线板老化了,就要停电去重新接.这样造成了忽然断电.对电脑硬盘损伤很大(已经报废了一个老硬盘了).本是自己安装一个teamviewer可以搞定的事,但是不知道为什么最近都是登录不进去(还有就是父母也不太会用).所以就想写一个通过手机可以控制电脑开关机的工具.还有一个问题,有时候孩子要在电脑看动画片或者他喜欢看的视频,本来是陪这他一起看,但是临时有事,出去了做事(如母猪产崽).结果时间长了孩子就过来找我.结果电脑就忘记关了.所以就更加迫使想做一个在手机上可以开关家里电脑的工具.可以在我自己我家人的手机上都安装一个.这样就可以不用在回到房间去关电脑了.只要拿出手机打开app几秒中就可以关闭家里的电脑省事.

设计分析

由于在局域网中手机是不知道每台电脑的IP,所以我们就用UDP广播的方式来确定每台开机的电脑的IP和MAC地址(要mac地址的目的就是为了开机用的)

然后说干就干C++写个WIN的简单UDP服务 核心代码如下:

   
DWORD UDPService::DoTask()
{
    sockSrv = socket( AF_INET , SOCK_DGRAM , 0 ) ;
    addrSrv.sin_addr.S_un.S_addr = htonl(INADDR_ANY) ;
    addrSrv.sin_family = AF_INET ;
    addrSrv.sin_port = htons(Get_GSet()->GetUdpPort()) ;

    bind(sockSrv , (SOCKADDR*)&addrSrv , sizeof(SOCKADDR));

    DWORD dwWaitRet = 3;
    while ( 1 )	 
    { 
        dwWaitRet = WaitForMultipleObjects(3, h_Events, FALSE, 100);
        if (dwWaitRet == WAIT_OBJECT_0 + 1)	 break;
        DoDispatcher(); 
    }

    closesocket( sockSrv );
    bIsRun  =  false;
    return 0;
} 
    
    
void UDPService::DoDispatcher()
{
    string strCmd;
    do 
    {
        if(!GetRecvData(strCmd)) break;

        if(!Dispatcher(strCmd)) break;

    } while (0);

}

bool UDPService::GetRecvData(string &strCmd)
{
    int len = sizeof(SOCKADDR); 
    int recvSize = sizeof(recvBuf); 

    ZeroMemory(recvBuf, recvSize);

    recvfrom(sockSrv,recvBuf, recvSize,0,(SOCKADDR*)&addrClient, &len);

    strFromIP = inet_ntoa(addrClient.sin_addr);
    strCmd = recvBuf; 

    LOG_INFO(L"recvfrom[%s]: %s\n", C2W(strFromIP).c_str(), C2W(strCmd).c_str());

    if(!GetCmdStrs(strCmd))
    {
        LOG_ERR(L"获取命令错误!");
        return false;
    }

    ZeroMemory(recvBuf, recvSize);
    strcpy(recvBuf, strCmd.c_str()); 
    return strCmd.length() > 2;
}

int UDPService::SendData(const string &sendDataStr)
{
    if (sendDataStr.length() GetCNameA(),
                Get_GSet()->GetURLA(),
                Get_GSet()->GetLOpenPort(),
                Get_GSet()->GetOpenPort(),
                Get_GSet()->GetClosePort()
                );  
        }      
        else 
        {
            sprintf_s(cmdBuffer,nBuffSize, "GetMacByIps Fial"); 
            OpenSuccess = false;
        } 

    }else if(nAt != string::npos)
    {
        //<shutdown:sToIp <reboot:sToIp        
        do 
        {
            string strCuuMac = strCmd.substr(nAt+1);
            string  strCmd1 = strCmd.substr(0, nAt); 
            ZeroMemory(cmdBuffer, nBuffSize);
            strcpy(cmdBuffer, strCmd1.c_str()); 

            LOG_INFO(C2W(cmdBuffer).c_str());


            if(!IpMgr.IsCuuPcByMac(strCuuMac))
            {
                bNeedSend = false;
                sprintf_s(cmdBuffer, sizeof(cmdBuffer), "IpMgr.IsCuuPcByMac(%s) == false ", strCuuMac.c_str());
                break;
            }

            if(stricmp(cmdBuffer, "shutdown") == 0)
            {  
                if(SystemShutdown())
                {
                    strcpy(cmdBuffer, "shutdown windows success");            
                }else{ 
                    sprintf_s(cmdBuffer, sizeof(cmdBuffer), "shutdown windows failed! ,error code is: %d", GetLastError());
                    OpenSuccess = false;
                }
            }else  if(stricmp(cmdBuffer, "reboot") == 0)
            {  
                if(SystemShutdown(true))
                {
                    strcpy(cmdBuffer, "reboot windows success"); 
                }else{ 
                    sprintf_s(cmdBuffer, sizeof(cmdBuffer), "reboot windows failed! ,error code is: %d", GetLastError());
                    OpenSuccess = false;
                }
            }
        } while (0); 

    }else {          
        sprintf_s(cmdBuffer, nBuffSize, "unkonw command [%s]", cmdBuffer); 
        OpenSuccess = false; 
    }

    string strData = cmdBuffer;
    if (OpenSuccess) LOG_INFO(C2W(strData).c_str());
    else LOG_ERR(C2W(strData).c_str()); 

    if(!bNeedSend) strData = "";

    return SendData(strData); 
}

手机端的核心代码如下:

package vip.caipiao365.CloseAssistant;

import android.os.Handler;
import android.os.Message;
import android.util.Log;

import org.json.JSONObject;

import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketTimeoutException;


public class udpBroadCast extends Thread {
    static public Handler uiHandler;
    MulticastSocket sendSocket = null;
    DatagramPacket dj = null;
    InetAddress group = null;
    // 确定要发送的消息:
    String mes = "";
    // 确定发送方的IP地址及端口号,地址为本地机器地址
    int port = 8910;
    String host = "255.255.255.255";// 广播地址
    int mType = 0;  // 0获取信息 // 1 关机  2 重启 3开机
    String sMac = "";


    // 接受反馈数据的缓冲存储器
    byte[] getBuf;
    // 接受类型的数据报
    DatagramPacket getPacket;

    public udpBroadCast(int nType, String _sToIp, String _sMac, int _port) {

        mType = nType;
        host = _sToIp;
        port = _port;
        sMac = _sMac;

        // 确定接受反馈数据的缓冲存储器,即存储数据的字节数组
        getBuf = new byte[2048];
        // 创建接受类型的数据报
        getPacket = new DatagramPacket(getBuf, getBuf.length);

        GetCmd();
    }

    protected HistoryItem JS2HistoryItem(JSONObject jsObj) {
        HistoryItem _item = new HistoryItem();

        _item.id = 0;
        try {
            _item.ip = jsObj.getString("I");
            _item.mac = jsObj.getString("M");
            _item.title = jsObj.getString("N");
            _item.cname = jsObj.getString("D");
            _item.url = jsObj.getString("U");
            _item.oport = jsObj.getInt("O");
            _item.port = jsObj.getInt("LO");
            _item.cport = jsObj.getInt("C");
        } catch (Exception e) {
            e.printStackTrace();
            _item = null;
        }
        return _item;
    }

    private HistoryItem parseJSONData(String jsonData) {
        HistoryItem _item = null;
        try {
            JSONObject jsonObject = new JSONObject(jsonData);
            _item = JS2HistoryItem(jsonObject);
        } catch (Exception e) {
            e.printStackTrace();
            _item = null;
        }
        return _item;
    }

    protected String GetData() {
        String strJson = "";
        try {
            // 通过套接字接受数据
            sendSocket.receive(getPacket);
            // 解析反馈的消息,并打印
            strJson = new String(getBuf, 0, getPacket.getLength());
        } catch (SocketTimeoutException e) {
            strJson = "";
        } catch (Exception e) {
            e.printStackTrace();
            strJson = "";
        }
        return strJson;
    }

    protected void GetCmd() {
        switch (mType) {
            // 0获取信息 // 1 关机  2 重启 3开机
            case 0:
                mes = "";
                MainActivity.mainAct.histHandler.ReSetComputStatus();
                break;
            case 1:
                mes = " 0) {
                ncount--;
                strJson = GetData();
                if (strJson.length() < 2) {
                    sleep(50);
                    continue;
                }

                HistoryItem _item = null;
                if (mType == 0) {
                    _item = parseJSONData(strJson);
                    if (_item != null) {
                        _item.starred = true;
                        Message msg = new Message();
                        msg.what = 1;
                        msg.obj = _item;
                        uiHandler.sendMessage(msg);
                        nCount++;
                    }
                } else if (mType != 0) {
                    Message msg = new Message();
                    msg.what = 6;
                    msg.obj = strJson;
                    uiHandler.sendMessage(msg);
                }
            }
            //sendSocket.leaveGroup(group);
            sendSocket.close();
        } catch (SocketTimeoutException e) {

        } catch (Exception e) {
            e.printStackTrace();
        }
        Message msg1 = new Message();
        msg1.what = 4;
        msg1.arg1 = nCount;
        uiHandler.sendMessage(msg1);
    }
}


本来设计的是从UDP获取的IP地址,然后在用TCP去连接发送关机重启指令,但是在我调试程序时候,有时候会报错误 No route to host.

想想UDP可以扫描有应答的报文,TCP链接有时候却抛这个异常.反正是局域网,而且数据量也不大就干脆用UDP广播得了.里面加上MAC地址,要是那台MAC地址配对上了就执行指令.


android端下载:  https://gitee.com/zuzong/Projects/raw/master/CloseAssistant/android/CloseAssistant.apk

电脑端下载:     https://gitee.com/zuzong/Projects/raw/master/CloseAssistant/PC/CloseAssistant.exe


注 要是哪位知道如何解决  No route to host.这个异常麻烦请指教

当时做完了局域网的开关机功能后.想要是有时离家远了手机搜不到家里wifi信号了.想要关机的话就用不了了.干脆就加个功能.实现在广域网的开关机.

由于我们的家里上网都是通过猫(或者光猫).这样造成我们的家里上网的IP是动态变化的.也就是说IP是不确定的.我们要来联系家里的电脑是没有办法的.这样的话就有一项服务产生了,那就是动态域名,当我们的路由器一链接网络.路由器就会去通知动态域名提供商.告诉他我这里最新的IP是多少.然后您要做的是申请一个动态域名然后绑定到家里路由器.

具体DDNS绑定路由器的方法很简单. 打开浏览器 进入您的路由器管理界面

然后找到 DDNS相关的设置 如下图:

添加相关的信息就OK了.没有的话就注册一个.

我用的是tp-link提供的如:


把路由器绑定了动态域名后还要做的一个操作就是端口映射.由于是家用的网络.家用理由器为了安全.关闭了外面访问家里内部网络的端口.所以想要在外面访问内部端口有两种方法.

  1. 防火墙穿透(就是打洞,但是由于网络的复杂性打洞的成功率不是100%.而且还要外网的一个服务器最好要有两个独立的公网ip.当时我在保千里工作时做了大量的测试和优化代码还是没有达到100%的成功率.)

  2. 直接在路由器里放开相应的断口

    因为是自家用的网络所以果断选择了第二种,几分钟设置完成.(应为打洞的话,目前我只有一个公网IP就是本站的服务器.一个公网IP打洞的成功率不是非常高)

    具体设置如下:
    a.mac地址绑定内网IP

    b.开放相应的端口

    上面图片只供参考,不同的路由器设置不一样.具体请看路由器的说明书或者网上搜相关的资料.

    就这样几分钟的时间,设置完成.可以在外网用关机助手开关机了.(本人自己亲测有效)


17年11份离职后在在调养身体时写的一些小工具


头条视频采集

开发语言:  python

适用平台:  windows, linux, macos

详细地址: http://caipiao365.vip/article/11

时间同步助手  

开发语言:  C++ 

适用平台: windows (xp及其以上的系统)

老电脑的福音, cmos电池没电的笔记本.主板系统时钟坏的的电脑可以用这个时间同步工具.

详细地址: http://caipiao365.vip/article/MyTime


开关机助手:

开发语言:  C++ , java

适用平台:  windows, android

懒人福利,想想在大冬天躺在被窝里看电影,看完后不想起来去关机是多么痛苦的一件事.想想本来家里的电脑是开这的,有时候因为有点事出去了一下,就忙忘记关机了.就想要是在手机上可以关闭该多好呀.所以这个软件就产生了.

详细地址: http://caipiao365.vip/CloseAssistant


关机助手电脑端设置说明

 安装服务   把本程序注册成windows服务程序

 删除服务   从windows服务中删除本程序

启动服务   安装成功后,从windows服务中启动本程序   

关闭服务    从windows服务中停止本程序  


记录信息和错误      记录程序运行生成的调试信息和错误信息   

只记录错误             只记录程序运行产生的错误信息

不记录日志             不记录任何日志

UDP端口               手机端UDP广播扫描PC端的UDP的端口,默认是8910,不要设置冲突的 


本机备注: 在手机上查看的计算机备注

内网开机端口:  局域网唤醒的 端口地址,默认是9.

外网地址:         这个是您家里路由器的动态域名

外网开机端口:  这个是您从外面如(手机网络,不是自家里的wifi)唤醒(打开)你家电脑的端口

外网关断端口:  这个是您从外面如(手机网络,不是自家里的wifi)关闭你家电脑的端口

外网相关的设置具体看: http://caipiao365.vip/article/19


**电脑端改了后,手机端口也要修改 电脑端修改后要重启一下服务使配置文件生效**  

手机端软件的设置


安装后打开手机app界面如下

刷新 按钮 的功能是手动刷新 当前局域网中的计算机开关机状态 (应为广域网和自动刷新的功能还没有做好)

内网: 默认是内网  在点一下就是外网 (选择当前操作是 内网开关机 还是外网)

点左上面的 按钮打开菜单 如下界面


点击设置打开系统全局设置界面 如:


UDP扫描断口: 和PC端要一致, 其他的设置暂时保留,自动刷新功能要用到的.