1、ping程序简单介绍

这个程序是Mike Muuss编写的。目的是測试另外一台机子是否可达。

运用的协议就是ICMP。运用的是ICMP的回显应答和请求回显两个类型。曾经呢。能ping通说明可以进行比方ftp。telnet等操作,不能ping通就不能做这种操作。

可是发展到如今。这个关系已经不成立了。非常多防火墙都可以屏蔽掉ping。

ICMP请求和回显报文格式:(图片是网上下载的一个)

能够看清楚当中的内容,ICMP报文格式太多了。所以针对的来说说。这个就是ping程序使用的ICMP报文。

注意当中几点:

第一、一般实现来说。ICMP报文中的标识符设置成发送进程的ID,这样即使一台机执行多个ping程序也不会混乱(unix就是这么做的。

)。

第二、客户发送的选项数据。必须回显。

这个我想我们ping一个IP地址。返回的内容非常多。比方:

回显的内容有字节,时间。ttl等。

这个有什么用。

计算时间就是一个样例:

ping计算时间是依据ICMP报文中存放的发送请求的时间来计算往返时间的。也就是说并非我们会自己记录一个时间。当应答返回。用当前时间减去ICMP报文中的时间值,就是往返时间。

对于ping,我们看到的是一个顺序的输出。req为1的在req为2的前面。可是实际上也可能出现同样的分组序号,还有N+1的序号在N之前的。这都可能出现,尤其是在广域网中进行ping。

ping提供了一个-R选项,提供记录路由功能。

记录路由功能就是将途经的路由器地址增加到IP数据包中。最多仅仅能放9个IP地址。由于首部长度60byte。IP头部20byte,减去3byte的路由记录功能的选项(也就是一些控制字段,比方类型。长度,指针)。剩下37bytes。仅仅能放9个IP地址了。

注意这个路由记录功能仅仅是记录出口IP地址。比方一个路由有2个IP地址链接两个不同的网络。记录仅仅是记录出口的IP地址。出。

最新的win8系统不支持-R选项。

ping是不经过TCP/UDP的。

2、traceroute\tracert

原理:

当路由器接受到一个IP数据包的时候,假设TLL为0或1就不转发该数据包,并给信息源发送一个ICMP超时信息。

这个ICMP信息的IP报文的信源地址是该路由器的IP地址(这是traceroute的关键)。

traceroute的做法是:

发送一个TTL为1的IP数据包给目的主机,处理这个数据包的第一个路由器将TTL减去1。丢弃数据包,并发送ICMP超时。这样就得到第一个路由器的IP地址了(这个在ICMP数据中有)。然后traceroute继续发送TTL为2的数据包给目的地址。这样就能够得到第二个路由IP。一直继续。那么怎么推断数据包到了目的地呢??

Traceroute程序发送IP数据包是包括UDP数据,可是udp选择一个不可能的值作为udpport,使不论什么一个应用都不可能使用该port。那么到达目的地的时候,主机将产生一个port不可达的ICMP错误。这样就能够通过推断返回的ICMP错误类型知道是否已经达到目的地了。

注意了。这个traceroute计算时间的跟ping不一样。traceroute是保存了数据包发送的时间。当收到一个icmp数据包的时候,得到系统当前时间,减去之前保存的时间就是RTT时间。

ping是在回显中存储了时间。所以ping更加可以准确。

为什么traceroute没有跟ping一样呢,由于ICMP仅仅返回出错的IP数据包的前8个字节,这8个字节就是udp的头部。因此没有返回traceroute存储的时间。

ICMP这个协议是IP的附属协议。由于它是用来控制差错的。所以很实用。

这个协议也是很复杂的。

附录:

以下来一个ping的源码。在linux 下执行(我是没有执行成功)

/**            P I N G . C** Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,* measure round-trip-delays and packet loss across network paths.** Author -*    Mike Muuss*    U. S. Army Ballistic Research Laboratory*    December, 1983* Modified at Uc Berkeley** Changed argument to inet_ntoa() to be struct in_addr instead of u_long* DFM BRL 1992** Status -*    Public Domain.  Distribution Unlimited.** Bugs -*    More statistics could always be gathered.*    This program has to run SUID to ROOT to access the ICMP socket.*/#include <stdio.h>
#include <errno.h>
#include <sys/time.h>#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <netdb.h>#define    MAXWAIT        10    /* max time to wait for response, sec. */
#define    MAXPACKET    4096    /* max packet size */
#define VERBOSE        1    /* verbose flag */
#define QUIET        2    /* quiet flag */
#define FLOOD        4    /* floodping flag */
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN    64
#endifu_char    packet[MAXPACKET];
int    i, pingflags, options;
extern    int errno;int s;            /* Socket file descriptor */
struct hostent *hp;    /* Pointer to host info */
struct timezone tz;    /* leftover */struct sockaddr whereto;/* Who to ping */
int datalen;        /* How much data */char usage[] =
"Usage:  ping [-dfqrv] host [packetsize [count [preload]]]\n";char *hostname;
char hnamebuf[MAXHOSTNAMELEN];int npackets;
int preload = 0;        /* number of packets to "preload" */
int ntransmitted = 0;        /* sequence # for outbound packets = #sent */
int ident;int nreceived = 0;        /* # of packets we got back */
int timing = 0;
int tmin = 999999999;
int tmax = 0;
int tsum = 0;            /* sum of all times, for doing average */
int finish(), catcher();
char *inet_ntoa();/**             M A I N*/
main(argc, argv)
char *argv[];
{struct sockaddr_in from;char **av = argv;struct sockaddr_in *to = (struct sockaddr_in *) &whereto;int on = 1;struct protoent *proto;argc--, av++;while (argc > 0 && *av[0] == '-') {while (*++av[0]) switch (*av[0]) {case 'd':options |= SO_DEBUG;break;case 'r':options |= SO_DONTROUTE;break;case 'v':pingflags |= VERBOSE;break;case 'q':pingflags |= QUIET;break;case 'f':pingflags |= FLOOD;break;}argc--, av++;}if(argc < 1 || argc > 4)  {printf(usage);exit(1);}bzero((char *)&whereto, sizeof(struct sockaddr) );to->sin_family = AF_INET;to->sin_addr.s_addr = inet_addr(av[0]);if(to->sin_addr.s_addr != (unsigned)-1) {strcpy(hnamebuf, av[0]);hostname = hnamebuf;} else {hp = gethostbyname(av[0]);if (hp) {to->sin_family = hp->h_addrtype;bcopy(hp->h_addr, (caddr_t)&to->sin_addr, hp->h_length);hostname = hp->h_name;} else {printf("%s: unknown host %s\n", argv[0], av[0]);exit(1);}}if( argc >= 2 )datalen = atoi( av[1] );elsedatalen = 64-8;if (datalen > MAXPACKET) {fprintf(stderr, "ping: packet size too large\n");exit(1);}if (datalen >= sizeof(struct timeval))    /* can we time 'em?

*/ timing = 1; if (argc >= 3) npackets = atoi(av[2]); if (argc == 4) preload = atoi(av[3]); ident = getpid() & 0xFFFF; if ((proto = getprotobyname("icmp")) == NULL) { fprintf(stderr, "icmp: unknown protocol\n"); exit(10); } if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) { perror("ping: socket"); exit(5); } if (options & SO_DEBUG) { if(pingflags & VERBOSE) printf("...debug on.\n"); setsockopt(s, SOL_SOCKET, SO_DEBUG, &on, sizeof(on)); } if (options & SO_DONTROUTE) { if(pingflags & VERBOSE) printf("...no routing.\n"); setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &on, sizeof(on)); } if(to->sin_family == AF_INET) { printf("PING %s (%s): %d data bytes\n", hostname, inet_ntoa(to->sin_addr), datalen); /* DFM */ } else { printf("PING %s: %d data bytes\n", hostname, datalen ); } setlinebuf( stdout ); signal( SIGINT, finish ); signal(SIGALRM, catcher); /* fire off them quickies */ for(i=0; i < preload; i++) pinger(); if(!(pingflags & FLOOD)) catcher(); /* start things going */ for (;;) { int len = sizeof (packet); int fromlen = sizeof (from); int cc; struct timeval timeout; int fdmask = 1 << s; timeout.tv_sec = 0; timeout.tv_usec = 10000; if(pingflags & FLOOD) { pinger(); if( select(32, &fdmask, 0, 0, &timeout) == 0) continue; } if ( (cc=recvfrom(s, packet, len, 0, &from, &fromlen)) < 0) { if( errno == EINTR ) continue; perror("ping: recvfrom"); continue; } pr_pack( packet, cc, &from ); if (npackets && nreceived >= npackets) finish(); } /*NOTREACHED*/ } /* * C A T C H E R * * This routine causes another PING to be transmitted, and then * schedules another SIGALRM for 1 second from now. * * Bug - * Our sense of time will slowly skew (ie, packets will not be launched * exactly at 1-second intervals). This does not affect the quality * of the delay and loss statistics. */ catcher() { int waittime; pinger(); if (npackets == 0 || ntransmitted < npackets) alarm(1); else { if (nreceived) { waittime = 2 * tmax / 1000; if (waittime == 0) waittime = 1; } else waittime = MAXWAIT; signal(SIGALRM, finish); alarm(waittime); } } /* * P I N G E R * * Compose and transmit an ICMP ECHO REQUEST packet. The IP packet * will be added on by the kernel. The ID field is our UNIX process ID, * and the sequence number is an ascending integer. The first 8 bytes * of the data portion are used to hold a UNIX "timeval" struct in VAX * byte-order, to compute the round-trip time. */ pinger() { static u_char outpack[MAXPACKET]; register struct icmp *icp = (struct icmp *) outpack; int i, cc; register struct timeval *tp = (struct timeval *) &outpack[8]; register u_char *datap = &outpack[8+sizeof(struct timeval)]; icp->icmp_type = ICMP_ECHO; icp->icmp_code = 0; icp->icmp_cksum = 0; icp->icmp_seq = ntransmitted++; icp->icmp_id = ident; /* ID */ cc = datalen+8; /* skips ICMP portion */ if (timing) gettimeofday( tp, &tz ); for( i=8; i<datalen; i++) /* skip 8 for time */ *datap++ = i; /* Compute ICMP checksum here */ icp->icmp_cksum = in_cksum( icp, cc ); /* cc = sendto(s, msg, len, flags, to, tolen) */ i = sendto( s, outpack, cc, 0, &whereto, sizeof(struct sockaddr) ); if( i < 0 || i != cc ) { if( i<0 ) perror("sendto"); printf("ping: wrote %s %d chars, ret=%d\n", hostname, cc, i ); fflush(stdout); } if(pingflags == FLOOD) { putchar('.'); fflush(stdout); } } /* * P R _ T Y P E * * Convert an ICMP "type" field to a printable string. */ char * pr_type( t ) register int t; { static char *ttab[] = { "Echo Reply", "ICMP 1", "ICMP 2", "Dest Unreachable", "Source Quench", "Redirect", "ICMP 6", "ICMP 7", "Echo", "ICMP 9", "ICMP 10", "Time Exceeded", "Parameter Problem", "Timestamp", "Timestamp Reply", "Info Request", "Info Reply" }; if( t < 0 || t > 16 ) return("OUT-OF-RANGE"); return(ttab[t]); } /* * P R _ P A C K * * Print out the packet, if it came from us. This logic is necessary * because ALL readers of the ICMP socket get a copy of ALL ICMP packets * which arrive ('tis only fair). This permits multiple copies of this * program to be run without having intermingled output (or statistics!). */ pr_pack( buf, cc, from ) char *buf; int cc; struct sockaddr_in *from; { struct ip *ip; register struct icmp *icp; register long *lp = (long *) packet; register int i; struct timeval tv; struct timeval *tp; int hlen, triptime; from->sin_addr.s_addr = ntohl( from->sin_addr.s_addr ); gettimeofday( &tv, &tz ); ip = (struct ip *) buf; hlen = ip->ip_hl << 2; if (cc < hlen + ICMP_MINLEN) { if (pingflags & VERBOSE) printf("packet too short (%d bytes) from %s\n", cc, inet_ntoa(ntohl(from->sin_addr))); /* DFM */ return; } cc -= hlen; icp = (struct icmp *)(buf + hlen); if( (!(pingflags & QUIET)) && icp->icmp_type != ICMP_ECHOREPLY ) { printf("%d bytes from %s: icmp_type=%d (%s) icmp_code=%d\n", cc, inet_ntoa(ntohl(from->sin_addr)), icp->icmp_type, pr_type(icp->icmp_type), icp->icmp_code);/*DFM*/ if (pingflags & VERBOSE) { for( i=0; i<12; i++) printf("x%2.2x: x%8.8x\n", i*sizeof(long), *lp++); } return; } if( icp->icmp_id != ident ) return; /* 'Twas not our ECHO */ if (timing) { tp = (struct timeval *)&icp->icmp_data[0]; tvsub( &tv, tp ); triptime = tv.tv_sec*1000+(tv.tv_usec/1000); tsum += triptime; if( triptime < tmin ) tmin = triptime; if( triptime > tmax ) tmax = triptime; } if(!(pingflags & QUIET)) { if(pingflags != FLOOD) { printf("%d bytes from %s: icmp_seq=%d", cc, inet_ntoa(from->sin_addr), icp->icmp_seq ); /* DFM */ if (timing) printf(" time=%d ms\n", triptime ); else putchar('\n'); } else { putchar('\b'); fflush(stdout); } } nreceived++; } /* * I N _ C K S U M * * Checksum routine for Internet Protocol family headers (C Version) * */ in_cksum(addr, len) u_short *addr; int len; { register int nleft = len; register u_short *w = addr; register u_short answer; register int sum = 0; /* * Our algorithm is simple, using a 32 bit accumulator (sum), * we add sequential 16 bit words to it, and at the end, fold * back all the carry bits from the top 16 bits into the lower * 16 bits. */ while( nleft > 1 ) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if( nleft == 1 ) { u_short u = 0; *(u_char *)(&u) = *(u_char *)w ; sum += u; } /* * add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return (answer); } /* * T V S U B * * Subtract 2 timeval structs: out = out - in. * * Out is assumed to be >= in. */ tvsub( out, in ) register struct timeval *out, *in; { if( (out->tv_usec -= in->tv_usec) < 0 ) { out->tv_sec--; out->tv_usec += 1000000; } out->tv_sec -= in->tv_sec; } /* * F I N I S H * * Print out statistics, and give up. * Heavily buffered STDIO is used here, so that all the statistics * will be written with 1 sys-write call. This is nice when more * than one copy of the program is running on a terminal; it prevents * the statistics output from becomming intermingled. */ finish() { putchar('\n'); fflush(stdout); printf("\n----%s PING Statistics----\n", hostname ); printf("%d packets transmitted, ", ntransmitted ); printf("%d packets received, ", nreceived ); if (ntransmitted) if( nreceived > ntransmitted) printf("-- somebody's printing up packets!"); else printf("%d%% packet loss", (int) (((ntransmitted-nreceived)*100) / ntransmitted)); printf("\n"); if (nreceived && timing) printf("round-trip (ms) min/avg/max = %d/%d/%d\n", tmin, tsum / nreceived, tmax ); fflush(stdout); exit(0); } //E*O*F ping.c//

给一个可以在windows下执行成功的ping。这个ping是别人写的,时间计算等跟官方的不一样,可是也可以执行得到结果。仅供參考。

// ping.cpp : 定义控制台应用程序的入口点。
//
/*
改程序ping自己和ping一些内网不存在IP,不会经过wireshark
*/
#include <tchar.h>
#include <winsock2.h>
#pragma comment(lib,"ws2_32")
#include <stdio.h>
#include <string.h>
#include "Ws2tcpip.h"
typedef struct icmp_hdr
{unsigned char   icmp_type;  // 类型unsigned char   icmp_code;  // 代码unsigned short  icmp_checksum; // 校验和//以下内容对于不同类型和代码有不同的内容unsigned short  icmp_id;  // 标识符unsigned short  icmp_sequence; // 序列号//以下是选项数据unsigned long   icmp_timestamp; // 时间戳
} ICMP_HDR, *PICMP_HDR;typedef struct _IPHeader  // 20字节的IP头
{UCHAR     iphVerLen;      // 版本和头长度(各占4位)UCHAR     ipTOS;          // 服务类型 USHORT    ipLength;       // 封包总长度,即整个IP报的长度USHORT    ipID;           // 封包标识。惟一标识发送的每个数据报USHORT    ipFlags;        // 标志UCHAR     ipTTL;          // 生存时间,就是TTLUCHAR     ipProtocol;     // 协议。可能是TCP、UDP、ICMP等USHORT    ipChecksum;     // 校验和ULONG     ipSource;       // 源IP地址ULONG     ipDestination;  // 目标IP地址
} IPHeader, *PIPHeader;USHORT checksum(USHORT* buff, int size)
{unsigned long cksum = 0;while(size>1){cksum += *buff++;size -= sizeof(USHORT);}// 是奇数if(size){cksum += *(UCHAR*)buff;}// 将32位的chsum高16位和低16位相加,然后取反cksum = (cksum >> 16) + (cksum & 0xffff);cksum += (cksum >> 16);  return (USHORT)(~cksum);
}int main(int argc, char* argv[])
{// Validate the parametersif (argc != 2) {printf("usage: %s ipv4 address\n", argv[0]);printf("  to return the host\n");printf("       %s 127.0.0.1\n", argv[0]);return 1;}WSADATA wsaData;WORD sockVersion = MAKEWORD(2, 2);//载入winsock库if(WSAStartup(sockVersion, &wsaData) != 0)return 0;//建立原始套接字SOCKET sRaw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);//超时时间int OutTime=100;//设置超时setsockopt(sRaw, IPPROTO_IP, IP_TTL, (char*)&OutTime, sizeof(OutTime));SOCKADDR_IN dest;dest.sin_family = AF_INET;dest.sin_port = htons(0);//填写ping主机地址char *host_name = argv[1];// If the user input is an alpha name for the host, use gethostbyname()// If not, get host by addr (assume IPv4)printf("ping %s...\n", host_name);if (isalpha(host_name[0])) {        /* host address is a name */struct hostent *remoteHost = gethostbyname(host_name);//能够ping域名dest.sin_addr.S_un.S_addr = *(u_long *) remoteHost->h_addr_list[0];} else dest.sin_addr.S_un.S_addr = inet_addr(argv[1]);char buff[sizeof(ICMP_HDR)];ICMP_HDR* pIcmp = (ICMP_HDR*)buff;char recvBuf[1024];SOCKADDR_IN from;int nLen = sizeof(from);while(TRUE){static int nCount = 0;int nRet;if(nCount++ == 4)break;//类型8pIcmp->icmp_type = 8;//代码0pIcmp->icmp_code = 0;//标识符为本进程idpIcmp->icmp_id = (USHORT)GetCurrentProcessId();//检验和先填充为0pIcmp->icmp_checksum = 0;//时间戳为系统执行时间pIcmp->icmp_timestamp = GetTickCount();//计算检验和pIcmp->icmp_checksum = checksum((USHORT*)buff, sizeof(ICMP_HDR) );//发送ICMP回显请求数据报nRet = sendto(sRaw, buff, sizeof(ICMP_HDR) , 0, (SOCKADDR *)&dest, sizeof(dest));//发送错误。提示并退出程序if(nRet == SOCKET_ERROR){printf(" sendto failed %d\n",WSAGetLastError());return 0;}nRet = recvfrom(sRaw, recvBuf, 1024, 0, (sockaddr*)&from, &nLen);if(nRet == SOCKET_ERROR){if(WSAGetLastError() == WSAETIMEDOUT){printf(" timed out\n");continue;}printf(" recvfrom failed \n");return 0;}//得到当前系统执行时间int nTick = GetTickCount();//得到IP首部IPHeader *Iphdr=(IPHeader*)recvBuf;//推断是其后是否是ICMP报文if(Iphdr->ipProtocol!=0x01){printf("this is not a icmp packet\n");return 0;}//定位到ICMP报文首部ICMP_HDR* pRecvIcmp = (ICMP_HDR*)(recvBuf + sizeof(IPHeader));//推断收到的报文是否和我们发送的报文相相应if(pRecvIcmp->icmp_id != GetCurrentProcessId()){printf("this is another icmp packet\n");return 0;}//输出ping主机的ipprintf("Reply from %s: ",inet_ntoa(from.sin_addr));//输出收到的字节数printf("bytes=%d ",nRet);//输出从发送数据报到收到数据报所经历的时间printf("time=%dms\n",nTick - pRecvIcmp->icmp_timestamp);//Sleep(100);}return 0;
}

參考书籍:《TCP/IP具体解释卷1》

ping and traceroute(tracert)相关推荐

  1. C++ 实现 ping 功能 域名(URL)解析实际 IP地址

    1.简述 一般情况下,我们想知道在当前电脑设备环境下,某一个网址能不能访问,最简单的方法是win + R 键 ,输入cmd,召唤cmd命令行程序,然后直接用ping命令 + 网址 来看返回的结果,那么 ...

  2. 虚拟机ping不通主机,但是主机可以ping通虚拟机(转载)

    我在Windows7系统安装了虚拟机,通过虚拟机安装了Ubuntu13.04,我设置的主机与虚拟机的连接方式是桥接,安装好后,发现虚拟机ping不通主机,但是主机可以ping通虚拟机. 我的操作是:关 ...

  3. IPv6连接测试通过,但是无法ping成功问题解决(记录)

    网站显示可以ipv6 公网访问 测试通过 我的无法ping成功原因 电脑本身防火墙拦截了 详细查看 微软的用户提问 我就是在cmd 管理员模式下使用这个命令 之后ping通了 这个命令 意思应该是IC ...

  4. 网络命令——traceroute、tracert(windows)

    traceroute 路由追踪 语法:traceroute 参数 ip / 域名 1.检测是否安装 traceroute rpm -qa | grep traceroute 2.可以用 yum apt ...

  5. 网络协议 -- ICMP协议(1) 报文格式

    互联网控制消息协议(英文:Internet Control Message Protocol,ICMP)是互联网协议族的核心协议之一.定义在RFC 792文档中. ICMP的消息大致可以分为两类:一类 ...

  6. 计算机网络(四)网络层 上

    由于要准备考试和网络层的知识很多,所以我将网络层的博客分为了上下两部分. 网络层提供的两种服务--虚电路服务和数据报服务 1. 虚电路服务 传统电信网提供的主要业务是提供电话服务.电信网使用昂贵的程控 ...

  7. 路由追踪——traceroute与tracert

    一.路由追踪 (一)路由跟踪,就是获取从主机A到达目标主机B这个过程中所有需要经过的路由设备的转发接口IP. (二)ICMP协议 Internet控制报文协议(internet control mes ...

  8. 游戏引擎全剖析(二)

    第6部分:  声音系统,音频APIs 声音系统 由于人们玩的游戏在种类和技术上的进步,声音和音乐近几年来在游戏中正逐渐变得重要起来(声音是一个实际游戏的可玩特点,比如在Thief和其它同类游戏中的听觉 ...

  9. IP地址(配置),MAC地址,DNS,电脑无法上网解决解决步骤

    一.IP地址: 1.关于IP与IP地址:       IP是英文Internet Protocol的缩写,意思是"网络之间互连的协议",也就是为计算机网络相互连接进行通信而设计的协 ...

  10. web安全性测试用例(输入、输出、SQL注入、跨站请求伪造(CSRF)、跨站脚本攻击(XSS))实实在在的干货

    https://www.cnblogs.com/qmfsun/p/3724406.html 建立整体的威胁模型,测试溢出漏洞.信息泄漏.错误处理.SQL 注入.身份验证和授权错误. 1.   输入验证 ...

最新文章

  1. @autowired注解_品Spring:对@Autowired和@Value注解的处理方法(文末附spring系列资源合集)...
  2. [js]设计模式小结对原型的修改
  3. C语言中使用库函数解析命令行参数
  4. 轻芒阅读距离今日头条还差一个即刻
  5. 目录 | 数据结构与剑指Offer系列推文合集
  6. 【离散数学中的数据结构与算法】二 欧几里得算法与裴蜀等式
  7. io_uring vs epoll ,谁在网络编程领域更胜一筹?
  8. jQuery: 合并表格中相同文本的相邻单元格
  9. Python getattr() 函数
  10. 网易云api及 asrsea 加密参数文档
  11. 论坛用的两个函数:积分计算排名和楼层函数
  12. 大数四则运算java(转)
  13. Hadoop系列-YARN RM HA 高可用集群
  14. Spring Boot 启动流程
  15. 2020年ROS机器人操作系统用户官方调查
  16. 杀毒软件可以查杀所有计算机病毒吗,杀毒软件可以查杀所有病毒吗
  17. Android系统应用开发
  18. Eclipse使用Log4j2的详细教程
  19. 【转载】外设使用Tips之MSCAN接收ID滤波器设置
  20. 基于FPGA的图像浮雕效果实现

热门文章

  1. eclipse bookmark的使用
  2. JFreeChart学习示例
  3. [笔记]3.软件代码中的BUG问题的一些记录
  4. SUSE12Sp3安装配置.net core 生产环境-总汇(持续更新中...)
  5. Asp.net MVC中如何实现依赖注入(DI)(二)
  6. WPF XMAL获取元素的父元素,子元素
  7. C# 不借助第三个变量实现两整数交换
  8. OpenFire 安装及配置
  9. 修正 Mui 下拉上拉刷新功能
  10. makefile中的wildcard和notdir和patsubst