C++代码实现网络Ping功能

目录
  • (一)main.cpp文件
  • (二)ping.h文件
    • (1)IP头结构体:
    • (2)ICMP头结构体:
    • (3)ICMP响应报文结构体:
    • (4)Ping类及相关变量的定义:
  • (三)ping.cpp文件
    • (1)char *m_szICMPData; BOOL m_bIsInitSucc;
    • (2)BOOL Ping(char *szDestIP, PingReply *pPingReply = NULL, DWORD dwTimeout = 2000);
    • (3)BOOL PingCore(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout);
    • (4)计算检验和
    • (5)计算毫秒级别的时间差

ping 127.0.0.1: 这个Ping命令被送到本地计算机的IP软件,该命令永不退出该计算机。

localhost是个操作系统的网络保留名,是127.0.0.1的别名。

ping www.baidu.com——对这个域名执行Ping命令,你的计算机必须先将域名转换成IP地址,通常是通过DNS服务器。

(一)main.cpp文件

// ConsoleApplication3.cpp : 定义控制台应用程序的入口点。
//
//程序应用:  ping命令是向目的主机发送ICMP报文,检验本地主机和远程的目的主机是否连接

#include <winsock2.h>
#include <stdio.h>
#include "ping.h"

int main(void)
{
	CPing objPing;                 //CPing类与对象

	char *szDestIP = "127.0.0.1";  //字符IP地址  //127.0.0.1 这个Ping命令被送到本地计算机的IP软件,该命令永不退出该计算机。localhost是个操作系统的网络保留名,是127.0.0.1的别名。//ping www.baidu.com——对这个域名执行Ping命令,你的计算机必须先将域名转换成IP地址,通常是通过DNS服务器。
	PingReply reply;	           //PingReply类与对象

	printf("Pinging %s with %d bytes of data:\n", szDestIP, DEF_PACKET_SIZE);	//ping 远端IP地址,32字节的数据

	while (TRUE)
	{
		objPing.Ping(szDestIP, &reply);//远端IP地址不为空(NULL),就返回true表示需要响应报文。远端IP空时不需要响应报文false。
		printf("Reply from %s: bytes=%d time=%ldms TTL=%ld\n", szDestIP, reply.m_dwBytes, reply.m_dwRoundTripTime, reply.m_dwTTL);  //字节数,时间,TTL生存时间
		Sleep(500);
	}

	return 0;
}

(二)ping.h文件

(1)IP头结构体:

IHL:首部长度。因为IP的头部不是定长的,所以需要这个信息进行IP包的解析,从而找到Data字段的起始点。   

另外注意这个IHL是以4个字节为单位的,所以首部实际长度是IHL*4字节。

Time to Live:生存时间,这个就是TTL了。

Data:这部分是IP包的数据,也就是ICMP的报文内容。

//1.IP头结构体:20字节
struct IPHeader
{
	BYTE m_byVerHLen;		//4位版本Version+4位首部长度IHL	1B
	BYTE m_byTOS;			//服务类型						1B=16b
	USHORT m_usTotalLen;	//总长度						2B=16b
	USHORT m_usID;			//标识							2B=16b
	USHORT m_usFlagFragOffset; //3位标志+13位片偏移=16位	2B=16b
	BYTE m_byTTL;			//TTL	生存时间    			1B=8b
	BYTE m_byProtocol;		//协议							1B=8b   为1时表示是ICMP报文
	USHORT m_usHChecksum;	//首部检验和					2B=16b
	ULONG m_ulSrcIP;		//源IP地址						4B=32b
	ULONG m_ulDestIP;		//目的IP地址					4B=32b
};

(2)ICMP头结构体:

类型Type、代码Code、校验和、标识符、序列号、ICMP数据

//ICMP报文由首部8B和数据段组成。
//首部为定长的8个字节,前4个字节是通用部分(类型1B/代码1B/校验和2B),后4个字节随报文类型的不同有所差异。

//2.ICMP头结构体 (标准ICMP头为8字节)
struct ICMPHeader
{
	BYTE m_byType;		 //类型   1B   type=8表示响应请求报文,type=0表示响应应答报文。
	BYTE m_byCode;		 //代码   1B   与type组合,表示具体的信息
	USHORT m_usChecksum; //检验和 2B   整个ICMP报文的检验和,包括Type、Code、...、Data。
	USHORT m_usID;		 //标识符 2B=16bits	用于标识本进程
	USHORT m_usSeq;		 //序列号 2B=16bits	用于判断回显应答数据报。
	ULONG m_ulTimeStamp; //时间戳(非标准ICMP头部)4B   //统计ping的往返时间的做法是,在ICMP报文的Data区域写入4个字节的时间戳。在收到应答报文时,取出这个时间戳与当前的时间对比即可。
};

(3)ICMP响应报文结构体:

//3.ICMP回答报文结构体
struct PingReply
{
	USHORT m_usSeq;         //ICMP包的序列号  2B
	DWORD m_dwRoundTripTime;//时间差		  4B  (word是2字节)
	DWORD m_dwBytes;        //数据所占字节数  4B
	DWORD m_dwTTL;          //TTL生存时间     4B
};

(4)Ping类及相关变量的定义:

//类
class CPing
{
//公共变量
public:
	CPing();  //构造函数
	~CPing(); //析构函数

	BOOL Ping(DWORD dwDestIP, PingReply *pPingReply = NULL, DWORD dwTimeout = 2000);
	BOOL Ping(char *szDestIP, PingReply *pPingReply = NULL, DWORD dwTimeout = 2000);

//私有变量
private:
	BOOL PingCore(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout);
	USHORT CalCheckSum(USHORT *pBuffer, int nSize);//计算检验和
	ULONG GetTickCountCalibrate();  //计算毫秒级别的时间差

private:
	SOCKET m_sockRaw;			//需要监听的socket
	WSAEVENT m_event;           //网络事件对象
	USHORT m_usCurrentProcID;   //当前进程发出的报文
	char *m_szICMPData;			//ICMP(Internet Control Message Protocol,网际控制报文协议)
	BOOL m_bIsInitSucc;			//初始化成功

private:
	static USHORT s_usPacketSeq;  //序列号++(16位=2字节)
};

(三)ping.cpp文件

#include "ping.h"
#include <iostream>

USHORT CPing::s_usPacketSeq = 0;

(1)char *m_szICMPData; BOOL m_bIsInitSucc;

//::表示类作用域。为避免不同的类有名称相同的成员而采用作用域的方式进行区分。
CPing::CPing() :m_szICMPData(NULL), m_bIsInitSucc(FALSE)
{
	WSADATA WSAData;
	//WSAStartup(MAKEWORD(2, 2), &WSAData);
	if (WSAStartup(MAKEWORD(1, 1), &WSAData) != 0)
	{
		printf("WSAStartup() failed: %d\n", GetLastError());  /*如果初始化不成功则报错,GetLastError()返回发生的错误信息*/
		return;
	}

	m_event = WSACreateEvent();  //创建一个网络事件对象(HANDLE m_event)。   //返回一个手工重置的事件对象句柄 (HANDLE hEventObject)
	m_usCurrentProcID = (USHORT)GetCurrentProcessId();  //当前进程ID

	/*ICMP必须使用原始套接字进行设计,要手动设置IP的头部和ICMP的头部并行校验*/
	m_sockRaw = WSASocket(AF_INET, SOCK_RAW, IPPROTO_ICMP, NULL, 0, 0);  //创建一个监听的socket (SOCKET m_sockRaw)  //当IP报头中的协议字段值为1时,就说明这是一个ICMP报文。

	if (m_sockRaw == INVALID_SOCKET) //无效套接字
	{
		std::cerr << "WSASocket() failed:" << WSAGetLastError() << std::endl;  //10013 以一种访问权限不允许的方式做了一个访问套接字的尝试。
	}
	else  //是ICMP报文,令初始化成功,为ICMP数据分配内存
	{
		WSAEventSelect(m_sockRaw, m_event, FD_READ);  //调用WSAEventSelect将监听的socket(m_sockRaw)与该事件(m_event)进行关联。WSAEventSelect(套接字,网络事件对象,需要关注的事件)
		m_bIsInitSucc = TRUE;

		m_szICMPData = (char*)malloc(DEF_PACKET_SIZE + sizeof(ICMPHeader));  //为ICMPData分配内存

		//ping命令的工作原理是:向网络上的另一个主机系统发送ICMP报文,如果指定系统得到了报文,它将把报文一模一样地传回给发送者

		if (m_szICMPData == NULL)
		{
			m_bIsInitSucc = FALSE;
		}
	}
}

CPing::~CPing()
{
	WSACleanup();

	if (NULL != m_szICMPData)
	{
		free(m_szICMPData);
		m_szICMPData = NULL;
	}
}

(2)BOOL Ping(char *szDestIP, PingReply *pPingReply = NULL, DWORD dwTimeout = 2000);

BOOL CPing::Ping(char *szDestIP, PingReply *pPingReply, DWORD dwTimeout)
{
	if (NULL != szDestIP)	//远端IP非空
	{
		return PingCore(inet_addr(szDestIP), pPingReply, dwTimeout);  //项目 -> 属性 -> C/C++ > SDL检查:否。——修改VS配置,告诉它我就要用旧函数。inet_pton() or InetPton()
	}
	return FALSE;           //远端IP为空,false
}

(3)BOOL PingCore(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout);

1.//判断初始化是否成功

2.//配置套接字SOCKET

3.//构建ICMP包

4.//填补ICMP首部

5.//发送ICMP请求报文(ping请求)

6.//判断是否需要接收响应报文

7.//等待网络事件接收响应报文

BOOL CPing::PingCore(DWORD dwDestIP, PingReply *pPingReply, DWORD dwTimeout)
{
	//判断初始化是否成功
	if (!m_bIsInitSucc)
	{
		return FALSE;   //初始化没成功
	}

	//配置套接字SOCKET
	sockaddr_in sockaddrDest;                    //sockaddr_in是internet环境下的套接字地址。定义在ws2def.h中的结构体
	sockaddrDest.sin_family = AF_INET;           //地址族(Address Family):网络类型
	sockaddrDest.sin_addr.s_addr = dwDestIP;     //32位IP地址(4字节)
	int nSockaddrDestSize = sizeof(sockaddrDest);//大小

	//构建ICMP包
	int nICMPDataSize = DEF_PACKET_SIZE + sizeof(ICMPHeader);  //ICMP包长度:32+ICMP头
	ULONG ulSendTimestamp = GetTickCountCalibrate();    //发送时间戳(毫秒级)
	USHORT usSeq = ++s_usPacketSeq;						//2字节,++0
	memset(m_szICMPData, 0, nICMPDataSize);				//数据,长度。memset()初始化内存:
	//memset(* Dst, int Val, size_t Size):将指针变量Dst所指向的前Size字节的内存单元用一个“整数”Val替换。

	//填补ICMP首部
	ICMPHeader *pICMPHeader = (ICMPHeader*)m_szICMPData;
	pICMPHeader->m_byType = ECHO_REQUEST;   //类型。Type:8,Code:0:表示回显请求报文(ping请求)。   Type:0,Code:0:表示回显回答报文(ping应答)
	pICMPHeader->m_byCode = 0;              //代码
	pICMPHeader->m_usID = m_usCurrentProcID;//标识符
	pICMPHeader->m_usSeq = usSeq;           //本报的序列号
	pICMPHeader->m_ulTimeStamp = ulSendTimestamp;//发送时间戳(非标准ICMP头部)
	pICMPHeader->m_usChecksum = CalCheckSum((USHORT*)m_szICMPData, nICMPDataSize);//计算检验和    //TCP/IP协议栈使用的校验算法:对16位的数据进行累加计算,并返回计算结果

	//————————————————————————————————————————————————————————————————————————————————————————————
	//发送ICMP请求报文(ping请求)
	if (sendto(m_sockRaw, m_szICMPData, nICMPDataSize, 0, (struct sockaddr*)&sockaddrDest, nSockaddrDestSize) == SOCKET_ERROR)
	{
		return FALSE;  //套接字错误
	}

	//判断是否需要接收响应报文
	if (pPingReply == NULL)
	{
		return TRUE;
	}

	char recvbuf[256] = { "\0" };  //初始化

	while (TRUE)    //接收响应报文
	{
		//等待网络事件
		if (WSAWaitForMultipleEvents(1, &m_event, FALSE, 100, FALSE) != WSA_WAIT_TIMEOUT)  //等待事件(m_event)。
			//WSAWaitForMultipleEvents(事件对象数组里边的个数为1,事件对象数组,等待类型为FALSE表示事件数组里至少有一个信号就返回,等待的超时时间为100,当系统的执行队列有I/O例程要执行时不返回)
		{
			WSANETWORKEVENTS netEvent;
			WSAEnumNetworkEvents(m_sockRaw, m_event, &netEvent);   //m_event = WSACreateEvent();
			//事件发生时,调用WSAEnumNetworkEvents,检测指定的socket上的网络事件,并将关联信息保存在netEvent中。
			//WSAEnumNetworkEvents(SOCKET s,WSAEVENT hEventObject,LPWSANETWORKEVENTS lpNetworkEvents)
			//当调用WSAEnumNetworkEvents函数成功后,它会将我们指定的socket和事件对象所关联的网络事件的信息保存到LPWSANETWORKEVENTS这个结构体里去,根据这个结构体我们就可以判断是否是我们所关注的网络事件已经发生了。

			//如果是FD_READ,读的网络事件发生了,那就调用recv函数进行操作。
			//若是FD_CLOSE,关闭的网络事件发生了,就调用closesocket将socket关掉,在数组里将其置零等操作。
			if (netEvent.lNetworkEvents & FD_READ)  //有网络事件,且可读,那就recv收数啊
			{
				ULONG nRecvTimestamp = GetTickCountCalibrate();   //计算开始发送的时间
				int nPacketSize = recvfrom(m_sockRaw, recvbuf, 256, 0, (struct sockaddr*)&sockaddrDest, &nSockaddrDestSize);  //从远端IP处收数。
				if (nPacketSize != SOCKET_ERROR)
				{
					//ICMP协议是IP层的一个协议,但是由于差错报告在发送给报文源发方时可能也要经过若干子网,因此牵涉到路由选择等问题,所以ICMP报文需通过IP协议来发送。

					//ICMP数据报的数据发送前需要两级封装:首先添加ICMP报头形成ICMP报文,再添加IP报头形成IP数据报。
					//拆解封装:IP数据报去掉IP报头,剩下ICMP报文,再去掉ICMP报头,就是ICMP数据报了。
					IPHeader *pIPHeader = (IPHeader*)recvbuf;
					USHORT usIPHeaderLen = (USHORT)((pIPHeader->m_byVerHLen & 0x0f) * 4);     //(4位版本+4位首部长度)&0xf,然后乘4  //IP头部20字节
					ICMPHeader *pICMPHeader = (ICMPHeader*)(recvbuf + usIPHeaderLen);

					if (pICMPHeader->m_usID == m_usCurrentProcID //是当前进程发出的报文
						&& pICMPHeader->m_byType == ECHO_REPLY   //是响应报文类型(Type=0)
						&& pICMPHeader->m_usSeq == usSeq         //是本次请求报文的响应报文
						)
					{
						pPingReply->m_usSeq = usSeq;   //ICMP包的序列号
						pPingReply->m_dwRoundTripTime = nRecvTimestamp - pICMPHeader->m_ulTimeStamp; //当应答返回时,用当前时间减去存放在ICMP报文中的时间值,即是往返时间。
						pPingReply->m_dwBytes = nPacketSize - usIPHeaderLen - sizeof(ICMPHeader);//数据大小:整包数据-IP头-ICMP头
						pPingReply->m_dwTTL = pIPHeader->m_byTTL;  //TTL生存时间
						return TRUE;
					}
				}
			}
		}
		//超时
		if (GetTickCountCalibrate() - ulSendTimestamp >= dwTimeout)//时间戳(非标准ICMP头部)
		{
			return FALSE;
		}
	}
}

WSA连网事件流程图

(4)计算检验和

//计算检验和    // TCP/IP协议栈使用的校验算法是比较经典的,对16位的数据进行累加计算,并返回计算结果
USHORT CPing::CalCheckSum(USHORT *pBuffer, int nSize)       //CalCheckSum((USHORT*)m_szICMPData, nICMPDataSize);
{
	unsigned long ulCheckSum = 0;   //4B=32b    //(1)将检验和字段置为0

	while (nSize > 1)
	{
		ulCheckSum += *pBuffer++;   //数值相加	//(2)把需校验的数据看成以16位为单位的数字组成,依次进行求和,并存到32位的整型中
		nSize -= sizeof(USHORT);    //长度相减
	}
	if (nSize)
	{
		ulCheckSum += *(UCHAR*)pBuffer;
	}

	ulCheckSum = (ulCheckSum >> 16) + (ulCheckSum & 0xffff);  //高位相加  //(3)把求和结果中的高16位(进位)加到低16位上,如果还有进位,重复
	ulCheckSum += (ulCheckSum >> 16);                         //将溢出位加入

	return (USHORT)(~ulCheckSum);    //返回值:取反                       //(4)将这个32位的整型按位取反,并强制转换为16位整型(截断)后返回
}

/*
附录:如何计算检验和
ICMP中检验和的计算算法为:
1、将检验和字段置为0
2、把需校验的数据看成以16位为单位的数字组成,依次进行二进制反码求和
3、把得到的结果存入检验和字段中
所谓二进制反码求和,就是:
1、将源数据转成反码
2、0 + 0 = 0   0 + 1 = 1   1 + 1 = 0进1
3、若最高位相加后产生进位,则最后得到的结果要加1
在实际实现的过程中,比较常见的代码写法是:
1、将检验和字段置为0
2、把需校验的数据看成以16位为单位的数字组成,依次进行求和,并存到32位的整型中
3、把求和结果中的高16位(进位)加到低16位上,如果还有进位,重复第3步[实际上,这一步最多会执行2次]
4、将这个32位的整型按位取反,并强制转换为16位整型(截断)后返回
*/

(5)计算毫秒级别的时间差

//计算毫秒级别的时间差。返回值是unsigned long级别的
ULONG CPing::GetTickCountCalibrate()
{
	static ULONG s_ulFirstCallTick = 0;
	static LONGLONG s_ullFirstCallTickMS = 0;

	SYSTEMTIME systemtime;		//系统时间SYSTEMTIME与tm类似,不过多了一项wMilliseconds。
	FILETIME filetime;		    //文件时间FILETIME与time_t类似,是64位整型,不过FILETIME是以100纳秒(ns)为单位。
	GetLocalTime(&systemtime);  //GetLocalTime获得当前的本地时间,GetSystemTime函数获得当前的UTC时间,两个时间存在着时差。
	SystemTimeToFileTime(&systemtime, &filetime);//UTC的SYSTEMTIME时间 转换为对应的 本地的FILETIME时间

	LARGE_INTEGER liCurrentTime;
	liCurrentTime.HighPart = filetime.dwHighDateTime;
	liCurrentTime.LowPart = filetime.dwLowDateTime;
	LONGLONG llCurrentTimeMS = liCurrentTime.QuadPart / 10000;

	if (s_ulFirstCallTick == 0)
	{
		s_ulFirstCallTick = GetTickCount();  //返回(retrieve)从操作系统启动所经过(elapsed)的毫秒数。用GetTickCount()计算毫秒级的时间差是不靠谱的!
	}

	if (s_ullFirstCallTickMS == 0)
	{
		s_ullFirstCallTickMS = llCurrentTimeMS;
	}

	return s_ulFirstCallTick + (ULONG)(llCurrentTimeMS - s_ullFirstCallTickMS);//   当前时间ms - 第一次回应时间ms
}

到此这篇关于C++代码实现网络Ping功能的文章就介绍到这了,更多相关C++网络Ping内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 用C/C++代码检测ip能否ping通(配合awk和system可以做到批量检测)

    遇到一个小需求, 快速搞定. 来看看用C/C++代码检测ip能否ping通: #include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> using namespace std; string getCmdResult(const string &strCmd) // 这个是获取命令执行的结果, 类似于

  • C++实现获取IP、子网掩码、网关、DNS等本机网络参数的方法

    本文以一个完整实例形式介绍了C++实现获取IP.子网掩码.网关.DNS等本机网络参数的方法,供大家参考,具体的完整实例如下: #pragma comment(lib,"Ws2_32.lib") #include <Iphlpapi.h> #pragma comment(lib, "Iphlpapi.lib") using namespace std; typedef struct tagNetworkCfg { char szIP[18]; char s

  • C++设置系统时间及系统时间网络更新的方法

    本文实例讲述了C++设置系统时间及系统时间网络更新的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: //根据返回的时间设置系统时间 void setTimeFromTP(ULONG ulTime) {      FILETIME ft;      SYSTEMTIME st;        //将基准时间转换成windows文件时间      st.wYear = 1900;      st.wMonth = 1;      st.wDay = 1;      st.wHo

  • C++实现ping程序实例

    本文实例讲述了C++实现ping程序的方法.分享给大家供大家参考.具体实现方法如下: 该实例涉及ICMP数据包的发送与回显,PING程序代码如下: 复制代码 代码如下: DWORD WINAPI ThreadProc(LPVOID lParam) {  CInitSock initSock;    HWND hWnd = (HWND)lParam; //从参数得到句柄  char szIp[64] ={0};  ::GetDlgItemTextA(hWnd, IDC_IP, szIp, size

  • C++代码实现网络Ping功能

    目录 (一)main.cpp文件 (二)ping.h文件 (1)IP头结构体: (2)ICMP头结构体: (3)ICMP响应报文结构体: (4)Ping类及相关变量的定义: (三)ping.cpp文件 (1)char *m_szICMPData; BOOL m_bIsInitSucc; (2)BOOL Ping(char *szDestIP, PingReply *pPingReply = NULL, DWORD dwTimeout = 2000); (3)BOOL PingCore(DWORD

  • IOS代码笔记之网络嗅探功能

    本文实例为大家分享了IOS网络嗅探工具,供大家参考,具体内容如下 一.效果图    二.工程图   三.代码 AppDelegate.h #import <UIKit/UIKit.h> #import "Reachability.h" @interface AppDelegate : UIResponder <UIApplicationDelegate> { Reachability *reachability; BOOL WarningViaWWAN; } @

  • 详解Python网络爬虫功能的基本写法

    网络爬虫,即Web Spider,是一个很形象的名字.把互联网比喻成一个蜘蛛网,那么Spider就是在网上爬来爬去的蜘蛛. 1. 网络爬虫的定义 网络蜘蛛是通过网页的链接地址来寻找网页的.从网站某一个页面(通常是首页)开始,读取网页的内容,找到在网页中的其它链接地址,然后通过这些链接地址寻找下一个网页,这样一直循环下去,直到把这个网站所有的网页都抓取完为止.如果把整个互联网当成一个网站,那么网络蜘蛛就可以用这个原理把互联网上所有的网页都抓取下来.这样看来,网络爬虫就是一个爬行程序,一个抓取网页的

  • Python实现可获取网易页面所有文本信息的网易网络爬虫功能示例

    本文实例讲述了Python实现可获取网易页面所有文本信息的网易网络爬虫功能.分享给大家供大家参考,具体如下: #coding=utf-8 #--------------------------------------- # 程序:网易爬虫 # 作者:ewang # 日期:2016-7-6 # 语言:Python 2.7 # 功能:获取网易页面中的文本信息并保存到TXT文件中. #--------------------------------------- import string impor

  • Android中实现ping功能的多种方法详解

    使用java来实现ping功能. 并写入文件.为了使用java来实现ping的功能,有人推荐使用java的 Runtime.exec()方法来直接调用系统的Ping命令,也有人完成了纯Java实现Ping的程序,使用的是Java的NIO包(native io, 高效IO包).但是设备检测只是想测试一个远程主机是否可用.所以,可以使用以下三种方式来实现: 1. Jdk1.5的InetAddresss方式 自从Java 1.5,java.net包中就实现了ICMP ping的功能. 使用时应注意,如

  • 纯Javascript实现ping功能的方法

    本文实例讲述了纯Javascript实现ping功能的方法.分享给大家供大家参考.具体实现方法如下: function ping(ip) { var img = new Image(); var start = new Date().getTime(); var flag = false; var isCloseWifi = true; var hasFinish = false; img.onload = function() { if ( !hasFinish ) { flag = true

  • 对textarea框的代码调试,而且功能上使用非常方便,酷

    <HTML><HEAD><META http-equiv='Content-Type' content='text/html; charset=gb2312'><TITLE>对textarea框的代码调试,而且功能上使用非常方便,酷</TITLE></HEAD><BODY > <SCRIPT>function JM_cc(ob){ob.select();js=ob.createTextRange();js.ex

  • python使用xmlrpclib模块实现对百度google的ping功能

    本文实例讲述了python使用xmlrpclib模块实现对百度google的ping功能.分享给大家供大家参考.具体分析如下: 最近在做SEO的时候,为了让发的外链能够快速的收录,想到了利用ping的功能,google和百度都有相关的ping介绍,有兴趣的朋友可以去看看相关的知识.实现ping功能除了可以用一些开源的博客程序,比如WP,它是可以在后台设置ping地址的,只要设置好以后,你发帖子,就会自动的通知搜索引擎,我的博客已经更新了,而今天我用的方法是不通过WP等带有ping功能的博客,自己

  • 50行Python代码实现人脸检测功能

    现在的人脸识别技术已经得到了非常广泛的应用,支付领域.身份验证.美颜相机里都有它的应用.用iPhone的同学们应该对下面的功能比较熟悉 iPhone的照片中有一个"人物"的功能,能够将照片里的人脸识别出来并分类,背后的原理也是人脸识别技术. 这篇文章主要介绍怎样用Python实现人脸检测.人脸检测是人脸识别的基础.人脸检测的目的是识别出照片里的人脸并定位面部特征点,人脸识别是在人脸检测的基础上进一步告诉你这个人是谁. 好了,介绍就到这里.接下来,开始准备我们的环境. 准备工作 本文的人

  • vue中子组件向父组件传递数据的实例代码(实现加减功能)

    这里讲解一下子组件向父组件传递值的常用方式. 这里通过一个加减法的实例向大家说明一下,这个的原理. 如下图所示: 当没有任何操作的时候父组件的值是 0 当点击加号以后父组件的值是 1 当点击减号以后父组件的值是减一变成 0 具体代码我直接贴出来,刚出炉的代码. <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name=&qu

随机推荐