在C++中实现ping功能,并不难。但真正了解ping是需要花费一番功夫的。

Ping功能是在ICMP基础上实现的。IP协议并不是一个可靠的协议,它不保证数据被送达,那么,保证数据送达的工作应该由其他的模块来完成。其中一个重要的模块就是ICMP(网络控制报文)协议。ICMP主要是用来实现IP系统间传递差错和管理报文,是任何IP实现必须和要求的组成部分。它是TCP/IP协议族的一个子协议,属于网络层协议。ICMP提供一致易懂的出错报告信息。发送的出错报文返回到发送原数据的设备,因为只有发送设备才是出错报文的逻辑接受者。发送设备随后可根据ICMP报文确定发生错误的类型,并确定如何才能更好地重发失败的数据包。当传送IP数据包发生错误--比如主机不可达,路由不可达等等,ICMP协议将会把错误信息封包,然后传送回给主机。给主机一个处理错误的机会,这也就是为什么说建立在IP层以上的协议是可能做到安全的原因。

。在程序中实现Ping功能时,常用的方法有三:

一、调用system实现

#include <windows.h>
#include <stdio.h>
#include <string.h>
char YN(int k) {FILE *f;char fn[40];char ln[80];char yn;int n;yn='N';sprintf(fn,"d:\\ping%d.txt",k);f=fopen(fn,"r");if (NULL!=f) {n=0;while (1) {if (NULL==fgets(ln,80,f)) break;//if (strstr(ln,"ms ")) {yn='Y';break;//}n++;if (n>=4) break;//}fclose(f);}return yn;
}
void main(int argc,char **argv) {char cmdstr[256];int i;int IP[3];char c;if (argc<2) {USAGE:printf("Usage example:\n    %s 192.168.60.\nto test 192.168.60.1-254\n",argv[0]);return;}if (4==sscanf(argv[1],"%d.%d.%d%c",&IP[0],&IP[1],&IP[2],&c)) {if (0<=IP[0] && IP[0]<=255&& 0<=IP[1] && IP[1]<=255&& 0<=IP[2] && IP[2]<=255&& '.'==c) {for (i=1;i<255;i++) {sprintf(cmdstr,"cmd /c ping %s%d -n 1 -w 1000 >d:\\ping%d.txt",argv[1],i,i);WinExec(cmdstr,SW_HIDE);}Sleep(3000);for (i=1;i<255;i++) {printf("%c %s%d\n",YN(i),argv[1],i);}Sleep(3000);WinExec("cmd /c del /q d:\\ping*.txt",SW_HIDE);} else goto USAGE;} else goto USAGE;
}

二、使用socket协议实现

// MyPing.cpp : Defines the entry point for the console application.//
#include "stdafx.h"#include <winsock2.h>#include <WS2tcpip.h>#include <stdio.h>#include <stdlib.h>#define ICMP_ECHO 8#define ICMP_ECHOREPLY 0#define ICMP_MIN 8 //Minimum 8-byte ICMP packet (header)#define DEF_PACKET_SIZE 32#define MAX_PACKET 1024#define MAX_IP_HDR_SIZE 60//IP header structuretypedef struct _iphdr{unsigned int h_len:4;//Length of the headerunsigned int version:4;//Version of IPunsigned char tos;//Type of serviceunsigned short total_len;//Total length of the packetunsigned short ident;//Unique identifierunsigned short frag_and_flags;//Flagsunsigned char ttl;//Time to liveunsigned char proto;//Protocol (TCP,UDP,etc.)unsigned short checksum;//IP checksumunsigned int sourceIP;unsigned int destIP;} IpHeader;//ICMP header structuretypedef struct _icmphdr{BYTE i_type;BYTE i_code;//Type sub codeUSHORT i_cksum;USHORT i_id;USHORT i_seq;//This is not the standard header, but we reserve space for timeULONG timestamp;} IcmpHeader;//IP option header--use with socket option IP_OPTIONStypedef struct _ipoptionhdr{unsigned char code;//Option typeunsigned char len;//Length of option hdrunsigned char ptr;//Offset into optonsunsigned long addr[9];//List of IP addrs} IpOptionHeader;int datasize;char* lpdest;//Print usage informationvoid usage(){printf("usage:MyPing -i:IP [data size]\n");printf("    -i:IP           remote machine to Ping\n");printf("    datasize     can be up to 1 KB\n");ExitProcess(1);}//Helper function to fill in various fields for our ICMP requestvoid FillICMPData(char* icmp_data, int datasize){IcmpHeader* icmp_hdr = (IcmpHeader*)icmp_data;icmp_hdr->i_type = ICMP_ECHO;//Request an ICMP echoicmp_hdr->i_code = 0;icmp_hdr->i_id = (USHORT)GetCurrentProcessId();icmp_hdr->i_cksum = 0;icmp_hdr->i_seq = 0;char* datapart = icmp_data + sizeof(IcmpHeader);//Place some junk in the buffermemset(datapart, 'E', datasize - sizeof(IcmpHeader));}//This function calculates the 16-bit one's complement sum//of the supplied buffer (ICMP) headerUSHORT checksum(USHORT* buffer, int size){unsigned long cksum = 0;while (size > 1){cksum += *buffer++;size -= sizeof(USHORT);}if (size){cksum += *(UCHAR*)buffer;}cksum = (cksum>>16) + (cksum & 0xffff);cksum += (cksum>>16);return (USHORT)(~cksum);}//If the IP option header is present, find the IP options//within the IP header and print the record route option valuesvoid DecodeIPOptions(char* buf, int bytes){IpOptionHeader* ipopt = (IpOptionHeader*)(buf + 20);printf("RR:    ");for (int i = 0; i < (ipopt->ptr / 4) - 1; i++){IN_ADDR inaddr;inaddr.S_un.S_addr = ipopt->addr[i];if (i != 0){printf("        ");}HOSTENT* host = gethostbyaddr((char*)&inaddr.S_un.S_addr,sizeof(inaddr.S_un.S_addr), AF_INET);if (host){printf("(%-15s) %s\n", inet_ntoa(inaddr), host->h_name);}else{printf("(%-15s)\n", inet_ntoa(inaddr));}}return;}//The response is an IP packet. We must decode the IP header to//locate the ICMP data.void DecodeICMPHeader(char* buf, int bytes, struct sockaddr_in* from){static int icmpcount = 0;IpHeader* iphdr = (IpHeader*)buf;//Number of 32-bit words * 4 = bytesunsigned short iphdrlen = iphdr->h_len * 4;DWORD tick = GetTickCount();if ((iphdrlen == MAX_IP_HDR_SIZE) && (!icmpcount)){DecodeIPOptions(buf, bytes);}if (bytes < iphdrlen + ICMP_MIN){printf("Too few bytes from %s\n", inet_ntoa(from->sin_addr));}IcmpHeader* icmphdr = (IcmpHeader*)(buf + iphdrlen);if (icmphdr->i_type != ICMP_ECHOREPLY){printf("nonecho type %d recvd\n", icmphdr->i_type);return;}//Make sure this is an ICMP reply to something we sent!if (icmphdr->i_id != (USHORT)GetCurrentProcessId()){printf("someone else's packet!\n");return;}printf("%d bytes from %s:", bytes, inet_ntoa(from->sin_addr));printf("  icmp_seq = %d. ", icmphdr->i_seq);printf("  time:%d ms", tick - icmphdr->timestamp);printf("\n");icmpcount++;return;}void ValidateArgs(int argc, _TCHAR** argv){lpdest = NULL;datasize = DEF_PACKET_SIZE;for (int i = 1; i < argc; i++){if ((argv[i][0] == '-') || (argv[i][0] == '/')){switch (tolower(argv[i][1])){case 'i':lpdest = argv[i] + 3;break;default:usage();break;}}else if (isdigit(argv[i][0])){datasize = atoi(argv[i]);}}}int _tmain(int argc, _TCHAR* argv[]){WSADATA wsaData;if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){printf("WSAStartup() failed:%d\n", GetLastError());return -1;}ValidateArgs(argc, argv);SOCKET sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP,NULL, 0, WSA_FLAG_OVERLAPPED);if (sockRaw == INVALID_SOCKET){printf("WSASocket() failed:%d\n", WSAGetLastError());return -1;}//Set the send/recv timeout valuesstruct sockaddr_in from;int fromlen = sizeof(from);int timeout = 1000;int bread = setsockopt(sockRaw, SOL_SOCKET, SO_RCVTIMEO,(char*)&timeout, sizeof(timeout));if (bread == SOCKET_ERROR){printf("setsockopt(SO_RCVTIMEO) failed:%d\n", WSAGetLastError());return -1;}timeout = 1000;bread = setsockopt(sockRaw, SOL_SOCKET, SO_SNDTIMEO,(char*)&timeout, sizeof(timeout));if (bread == SOCKET_ERROR){printf("setsockopt(SO_SNDTIMEO) failed:%d\n", WSAGetLastError());return -1;}struct sockaddr_in dest;memset(&dest, 0, sizeof(dest));//Resolve the endpoint's name if necessarydest.sin_family = AF_INET;if ((lpdest != NULL) && strlen(lpdest) != 0){dest.sin_addr.s_addr = inet_addr(lpdest);}else{struct hostent* hp = gethostbyname(lpdest);if (hp != NULL){memcpy(&(dest.sin_addr), hp->h_addr, hp->h_length);dest.sin_family = hp->h_addrtype;printf("dest.sin_addr = %s\n", inet_ntoa(dest.sin_addr));}else{printf("gethostbyname() failed:%d\n", WSAGetLastError());return -1;}}//Create the ICMP packetdatasize += sizeof(IcmpHeader);char* icmp_data = (char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY, MAX_PACKET);if (!icmp_data){printf("HeapAlloc() failed:%d\n", GetLastError());return -1;}memset(icmp_data, 0, MAX_PACKET);FillICMPData(icmp_data, datasize);char* recvbuf = (char*)HeapAlloc(GetProcessHeap(),   HEAP_ZERO_MEMORY, MAX_PACKET);//Start sending/receiving ICMP packetsUSHORT seq_no = 0;while (true){static int nCount = 0;int bwrote;if (nCount++ == 4){break;}((IcmpHeader*)icmp_data)->i_cksum = 0;((IcmpHeader*)icmp_data)->timestamp = GetTickCount();((IcmpHeader*)icmp_data)->i_seq = seq_no++;((IcmpHeader*)icmp_data)->i_cksum = checksum((USHORT*)icmp_data, datasize);bwrote = sendto(sockRaw, icmp_data, datasize, 0,(struct sockaddr*)&dest, sizeof(dest));if (bwrote == SOCKET_ERROR){if (WSAGetLastError() == WSAETIMEDOUT){printf("timed out\n");continue;}printf("sendto() failed:%d\n", WSAGetLastError());return -1;}if (bwrote < datasize){printf("Wrote %d bytes\n", bwrote);}bread = recvfrom(sockRaw, recvbuf, MAX_PACKET, 0,(struct sockaddr*)&from, &fromlen);if (bread == SOCKET_ERROR){if (WSAGetLastError() == WSAETIMEDOUT){printf("timed out\n");continue;}printf("revefrom() failed:%d\n", WSAGetLastError());return -1;}DecodeICMPHeader(recvbuf, bread, &from);Sleep(1000);}//Cleanupif (sockRaw != INVALID_SOCKET){closesocket(sockRaw);}HeapFree(GetProcessHeap(), 0, recvbuf);HeapFree(GetProcessHeap(), 0, icmp_data);WSACleanup();return 0;}

三、使用Win API调用ICMP.DLL实现、

在这里需要注意的一点是,Windows平台实现ping功能,如果需要使用到IcmpParseReplies函数,需要涉及到两个动态库Icmp.dll和Iphlpapi.dll。IcmpParseReplies函数在Windows2000上面由Icmp.dll导出,而在 Windows XP及以后的版本是由Iphlpapi.dll导出的。通过调用LoadLibrary和GetProcAddress来检测IcmpParseReplies由哪个动态库导出。优先判断Iphlpapi.dll是否存在且有导出此函数,如果存在就使用此动态库,否则再判断Icmp.dll。

另外随着IP6的使用,如果业务上涉及到这一块,也应该要留意。

常用的函数有三个:IcmpCreateFile、IcmpSendEcho、IcmpCloseHandle。具体使用见下实例。

void Ping(char *pIPAddr)
{
HANDLE iHwnd;
iHwnd=IcmpCreateFile();
IPAddr pAddr;
pAddr=(IPAddr)inet_addr (pIPAddr);
icmp_echo_reply pData;
for(int i=1;i<=LoopSend;i++)
{
IcmpSendEcho(iHwnd,pAddr,NULL,0,NULL,(LPVOID)&pData,sizeof(icmp_echo_reply),0);
if (pData.Status==0)
{
printf("Ping测试返回的结果: Time=%dms TTL=%d \n",(int)pData.RoundTripTime,(int)pData.Options.Ttl);
}
else
{
printf("Ping测试失败...\n");
}
}
if (!IcmpCloseHandle(iHwnd)) printf("Close handle has Error!\n");
}

你可能会发现,用IcmpSendEcho 测试 127.0.0.1的时候,ICMP_ECHO_REPLY.RoundTripTime 会等于0

其实,这个函数是没有出错的,即使用Ping 127.0.0.1也是可以的

那么应该怎么去判断这个函数出错呢?

用 ICMP_ECHO_REPLY.Status 来获得测试状态(记住,当Status为0的时候,函数是正确运行的)

常量名

含义

IP_SUCCESS

0

状态是成功。

IP_BUF_TOO_SMALL

11001

答复缓冲区太小。

IP_DEST_NET_UNREACHABLE

11002

目标网络不可达。

IP_DEST_HOST_UNREACHABLE

11003

目标主机不可达。

IP_DEST_PROT_UNREACHABLE

11004

目的地的协议是遥不可及。

IP_DEST_PORT_UNREACHABLE

11005

目标端口不可达。

IP_NO_RESOURCES

11006

IP资源不足是可用的。

IP_BAD_OPTION

11007

指定了错误的IP选项。

IP_HW_ERROR

11008

一个硬件错误。

IP_PACKET_TOO_BIG

11009

包太大。

IP_REQ_TIMED_OUT

11010

请求超时。

IP_BAD_REQ

11011

一个坏的请求。

IP_BAD_ROUTE

11012

一个糟糕的路线。

IP_TTL_EXPIRED_TRANSIT

11013

在传输过程中的生存时间(TTL)的过期。

IP_TTL_EXPIRED_REASSEM

11014

在碎片重组过程中的生存时间过期。

IP_PARAM_PROBLEM

11015

一个参数的问题。

IP_SOURCE_QUENCH

11016

数据报到达太快,处理和数据报可能被丢弃。

IP_OPTION_TOO_BIG

11017

一个IP选项是太大了。

IP_BAD_DESTINATION

11018

一个坏的目的地。

IP_GENERAL_FAILURE

11050

一般故障。这个错误可以返回一些畸形的ICMP数据包

要了解Ping的原理,我们先来了解下ping命令的使用

通过发送“网际消息控制协议 (ICMP)”回响请求消息来验证与另一台 TCP/IP 计算机的 IP 级连接。回响应答消息的接收情况将和往返过程的次数一起显示出来。Ping 是用于检测网络连接性、可到达性和名称解析的疑难问题的主要 TCP/IP 命令。

语法

ping [-t] [-a] [-n Count] [-l Size] [-f] [-i TTL] [-v TOS] [-r Count] [-s Count] [{-j HostList | -k HostList}] [-w Timeout] [TargetName]

-t

指定在中断前 ping 可以持续发送回响请求信息到目的地。要中断并显示统计信息,请按 CTRL-BREAK。要中断并退出 ping,请按 CTRL-C。

-a

指定对目的地 IP 地址进行反向名称解析。如果解析成功,ping 将显示相应的主机名。

-n Count

指定发送回响请求消息的次数。默认值为 4。

-lSize

指定发送的回响请求消息中“数据”字段的长度(以字节表示)。默认值为 32。size 的最大值是 65,527。

-f

指定发送的回响请求消息带有“不要拆分”标志(所在的 IP 标题设为 1)。回响请求消息不能由目的地路径上的路由器进行拆分。该参数可用于检测并解决“路径最大传输单位 (PMTU)”的故障。

-i TTL

指定发送回响请求消息的 IP 标题中的 TTL 字段值。其默认值是是主机的默认 TTL 值。对于 Windows XP 主机,该值一般是 128。TTL 的最大值是 255。

-v TOS

指定发送回响请求消息的 IP 标题中的“服务类型 (TOS)”字段值。默认值是 0。TOS 被指定为 0 到 255 的十进制数。

-r Count

指定 IP 标题中的“记录路由”选项用于记录由回响请求消息和相应的回响应答消息使用的路径。路径中的每个跃点都使用“记录路由”选项中的一个值。如果可能,可以指定一个等于或大于来源和目的地之间跃点数的 Count。Count 的最小值必须为 1,最大值为 9。

-s Count

指定 IP 标题中的“Internet 时间戳”选项用于记录每个跃点的回响请求消息和相应的回响应答消息的到达时间。Count 的最小值必须为 1,最大值为 4。

-jPath

指定回响请求消息使用带有 HostList 指定的中间目的地集的 IP 标题中的“稀疏资源路由”选项。可以由一个或多个具有松散源路由的路由器分隔连续中间的目的地。主机列表中的地址或名称的最大数为 9,主机列表是一系列由空格分开的 IP 地址(带点的十进制符号)。

-k HostList

指定回响请求消息使用带有 HostList 指定的中间目的地集的 IP 标题中的“严格来源路由”选项。使用严格来源路由,下一个中间目的地必须是直接可达的(必须是路由器接口上的邻居)。主机列表中的地址或名称的最大数为 9,主机列表是一系列由空格分开的 IP 地址(带点的十进制符号)。

-w Timeout

指定等待回响应答消息响应的时间(以微妙计),该回响应答消息响应接收到的指定回响请求消息。如果在超时时间内未接收到回响应答消息,将会显示“请求超时”的错误消息。默认的超时时间为 4000(4 秒 )。

TargetName

指定目的端,它既可以是 IP 地址,也可以是主机名。

/?

在命令提示符显示帮助。

每个ICMP报文都有自己的格式,但它们开始的三个字段都是一样的:一个8位的报文类型(type)用来标识报文,一个8位的代码(code)用来 提供有关类型的进一步信息,一个16位的校验和(checksum)。(ICMP采用和IP相同的校验和算法,但ICMP校验和只覆盖ICMP报文)。这 里我们给出ICMP报文首部的数据结构:

struct ICMPHEADER

{

BYTE   i_type;               // 类型

BYTE   i_code;               // 代码

USHORT i_cksum;              // 首部校验和

USHORT i_id;                 // 标识

USHORT i_seq;                // 序列号

ULONG timestamp;             // 时间戳(选用)

};

下表表示了ICMP的报文类型及其含义:

TYPE

CODE

Description

Query

Error

0

0

Echo Reply——回显应答(Ping应答)

x

3

0

Network Unreachable——网络不可达

x

3

1

Host Unreachable——主机不可达

x

3

2

Protocol Unreachable——协议不可达

x

3

3

Port Unreachable——端口不可达

x

3

4

Fragmentation needed but no frag. bit set——需要进行分片但设置不分片比特

x

3

5

Source routing failed——源站选路失败

x

3

6

Destination network unknown——目的网络未知

x

3

7

Destination host unknown——目的主机未知

x

3

8

Source host isolated (obsolete)——源主机被隔离(作废不用)

x

3

9

Destination network administratively prohibited——目的网络被强制禁止

x

3

10

Destination host administratively prohibited——目的主机被强制禁止

x

3

11

Network unreachable for TOS——由于服务类型TOS,网络不可达

x

3

12

Host unreachable for TOS——由于服务类型TOS,主机不可达

x

3

13

Communication administratively prohibited by filtering——由于过滤,通信被强制禁止

x

3

14

Host precedence violation——主机越权

x

3

15

Precedence cutoff in effect——优先中止生效

x

4

0

Source quench——源端被关闭(基本流控制)

5

0

Redirect for network——对网络重定向

5

1

Redirect for host——对主机重定向

5

2

Redirect for TOS and network——对服务类型和网络重定向

5

3

Redirect for TOS and host——对服务类型和主机重定向

8

0

Echo request——回显请求(Ping请求)

x

9

0

Router advertisement——路由器通告

10

0

Route solicitation——路由器请求

11

0

TTL equals 0 during transit——传输期间生存时间为0

x

11

1

TTL equals 0 during reassembly——在数据报组装期间生存时间为0

x

12

0

IP header bad (catchall error)——坏的IP首部(包括各种差错)

x

12

1

Required options missing——缺少必需的选项

x

13

0

Timestamp request (obsolete)——时间戳请求(作废不用)

x

14

Timestamp reply (obsolete)——时间戳应答(作废不用)

x

15

0

Information request (obsolete)——信息请求(作废不用)

x

16

0

Information reply (obsolete)——信息应答(作废不用)

x

17

0

Address mask request——地址掩码请求

x

18

0

Address mask reply——地址掩码应答

转载于:https://www.cnblogs.com/guolixiucai/p/5547757.html

从C++实现Ping开始说起相关推荐

  1. linux下出现ping:unknown host www.baidu.com问题时的解决办法——ubuntu下局域网络的配置...

    如果ping域名的时候出现ping:unknown host  xxx.xxx 但是ping IP地址的时候可以通的话 可知是dns服务器没有配置好, 查看一下配置文件/etc/resolv.conf ...

  2. CMD——ping及用其检测网络故障

    Ping命令全称Packet Internet Grope,即因特网包探测器.通过调用ICMP(因特网控制报文协议),发送一份ICMP回显请求给目的主机,并等待返回ICMP回显应答.一般用来测试源主机 ...

  3. RedHat 7.0及CentOS 7.0禁止Ping的三种方法

    作者:荒原之梦 原文链接:http://zhaokaifeng.com/?p=538 前言: "Ping"属于ICMP协议(即"Internet控制报文协议") ...

  4. 【Ubuntu】ping: unknown host www.baidu.com

    1.问题描述 每次重新设置网络后,ping百度总是报错: $ ping www.baidu.com ping: unknown host www.baidu.com 2.原因分析 原因是:查看/etc ...

  5. 10 ping不通widwos7 windwos_弱电老司机总结的10种视频监控系统故障解决方法,学会,事半功倍...

    最近有许多的读者咨询关于视频监控系统维修方法的事情,有没有总结一些常见故障的解决方案呢?当然有的,今天分享一些常见故障解决方法. 正文: 视频监控系统通常出现摄像机没有画面.或者画面卡顿.丢失等情况, ...

  6. centos iptables关于ping

    配置iptables策略后,一般来说INPUT都是DROP然后配置需要通过的 当执行: iptables -P INPUT DROP 后,机器就不能被ping通了! 因为icmp没有添加到规则中! 于 ...

  7. 服务器ping你可以ping通,你ping服务器ping不同的解决方案!!

    这几天让公司的服务器弄的蛋疼啊!!三天两头的出问题,主管脸色不大好看,我这里也郁闷的要死.所以发誓一定要把好安全关!! 今天在自己的虚拟机上边装了一个winserver2003标准版,搭建好环境之后发 ...

  8. 响应因特网端口ping命令_如何使用Ping命令识别基本的Internet问题

    响应因特网端口ping命令 Next time you call your help desk, do you want to wow them with your networking knowle ...

  9. 电脑显示服务器地址无法ping通,网关无法Ping通故障及解决方法

    很多网络故障是常见问题,一般的三板斧方法就能解决问题,但有些故障容易让我们多走弯路,我们不妨拓宽故障排查范围,换换思路. 在与网络亲密接触的过程中,我们或多或少地会遇到一些网络故障,对于许多网络故障来 ...

  10. 海思涵科技WIFI认证服务器不在线,在海思平台外加一个usb wifi模块,mt7601 加载ok,配置网络ok,但不能ping通?...

    请教下:我用mt7601 usb wifi模块 加载驱动 配置网络后经常打印 PeerBeaconAtJoinAction(): Set CentralChannel=1 PeerBeaconAtJo ...

最新文章

  1. Android--学习路线指南
  2. 夏日炎炎,请照顾好你的电脑
  3. HashMap源码解析(JDK1.8)
  4. 探讨 .NET 4 新增的 SortedSet 类
  5. 深圳,本周日,华为云开发者大会,免费报名中
  6. gulp不生成打包文件_命令行输入gulp 无法生成压缩文件
  7. Java Web学习总结(29)——Java Web中的Filter和Interceptor比较
  8. 关于SpringBoot对junit4/junit5的整合
  9. django上云步骤
  10. 百度热力图颜色说明_揭秘!张家口100万人口热力图,看完你就知道房子该买哪里了...
  11. 新概念二册 Lesson 13 The Greenwood Boys绿林少年 (将来进行时)
  12. Wi-Fi 工作频段
  13. 解决 Xshell6|Xftp6 强制升级问题
  14. 15Echarts:复杂数据展示
  15. time.gmtime()获取的时间问题
  16. 【微信小程序】-- 自定义组件 -- 数据、方法和属性(三十三)
  17. 融汇小学计算机课程,《小学信息技术行走课堂》读书心得
  18. Mac外接磁盘使用哪种格式速度最快,NTFS?exFAT?HFS+?APFS?
  19. R语言结构方程SEM中的power analysis 效能检验分析
  20. 双路由设置上网与共享

热门文章

  1. android 类似QQ 换皮肤 实现思路 apk资源共享
  2. 【GStreamer源码分析】playbin播放test.wav加载插件过程分析
  3. 【图片编程】JPEG的文件格式
  4. 如何给iPhone(苹果手机)安装ipa文件
  5. uni开发的电影票返利系统 完美可运营
  6. 【Winform项目】零压健身房管理系统(项目展示),大作业,期末作业,课设,课程设计。源码分享
  7. 动态规划之最大K乘积问题
  8. mysql聚合函数伪列_Oracle函数学习应用总结
  9. Http Server的工作原理
  10. 如果是你阿里云轻量服务器和ECS共享型n4你怎么选?