IP报文解析(TCP、UDP、 ICMP)及代码分享(C++)

news/2024/5/18 14:00:25 标签: tcp/ip, udp, 网络

一、OSI模型与TCP/IP协议栈

1.1 OSI 7层模型:

应用层:
功能:用户接口,文件传输、电子邮件、虚拟终端、文件服务
设备:网关
协议:HTTP、TFTP、SMTP、FTP、SNMP、DNS、Telnet

表示层:
功能:数据的表示,压缩和加密
设备:网关
协议:无

会话层:
功能:会话的建立和结束
设备:网关
协议:无

传输层:
功能:提供端对端的接口
设备:网关
协议:TCP UDP

网络层:
功能:为数据报选择路由,寻址
设备:路由器
协议:IP、ICMP、IGMP、RIP

数据链路层:
功能:传输有地址的帧与错误校验功能
设备:交换机、网桥、网卡
协议:PPP、ARP、MTU、RARP、SLIP、CSLIP

物理层:
功能:传输比特流,以二进制数据形式在物理媒体上传输数据
设备:集线器、中继器
协议:IEEE802、IEEE802.2、ISO2110

在这里插入图片描述

1.2 数据封装过程:

![在这里插入图片描述](https://img-blog.csdnimg.cn/03677d210ad94f449f4495d5c3690ee3.png
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
图片来源:https://blog.csdn.net/shimazhuge/article/details/5382725?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-5-5382725-blog-78396507.235v29pc_relevant_default_base3&spm=1001.2101.3001.4242.4&utm_relevant_index=8

1.3 TCP/IP 4层模型:

应用层:
功能:用户接口,文件传输、电子邮件、虚拟终端、文件服务
设备:网关
协议:HTTP、TFTP、SMTP、FTP、SNMP、DNS、Telnet

传输层:
功能:提供端对端的接口
设备:网关
协议:TCP UDP

网络层:
功能:为数据报选择路由,寻址
设备:路由器
协议:IP、ICMP、IGMP、RIP

数据链路层:
功能:传输有地址的帧与错误校验功能
设备:交换机、网桥、网卡
协议:PPP、ARP、MTU、RARP、SLIP、CSLIP

二、报文解析

2.1 IP报文

2.1.1 IP报文格式

在这里插入图片描述
在这里插入图片描述

2.1.2 IP报文解析及校验和计算:

十六进制加法计算器:
https://www.9321.cn/digital-computation/hex-addition-calculator.php

crc校验:http://www.ip33.com/crc.html

在这里插入图片描述

在这里插入图片描述

2.2 UDP报文

2.1.1 UDP报文格式:

在这里插入图片描述

2.1.2 UDP报文解析及校验和计算:

UDP的校验和需要计算UDP首部加数据荷载部分,但也需要加上UDP伪首部。这个伪首部指,源地址、目的地址、UDP数据长度、协议类型(0x11),协议类型就一个字节,但需要补一个字节的0x0,构成12个字节。伪首部+UDP首部+数据一起计算校验和。

在这里插入图片描述

2.3 TCP报文

2.3.1 TCP报文格式

在这里插入图片描述
1> 16位源端口号,2个字节。客户端通常使用系统自动选择的临时端口号。
2> 16位目的端口号,2个字节。服务器的端口号。
3> 32位序号,4个字节。A与B连接后发送第一个报文段,序号值被系统分配随机一个值S,后续报文段的序号值为S + 偏移值(该报文段第一个字节在整个字节流中第几个字节,例如,某个TCP报文段传送的数据是字节流中的第1025~2048字节,那么该报文段的序号值就是ISN+1025)
4> 32位确认号,4个字节。用作对另一方发送来的TCP报文段的响应。其值是收到的TCP报文段的序号值加1
5> 4位头部长度,表示有多少个32位字(4字节),4位最大值是15,所以头部最长60字节。
6> 6位保留。
7> 6位,ACK: 表示确认号是否有效。 PSH: 提示接收端应用程序应该立即从TCP接收缓冲区中读走数据。RST: 表示要求对方重新建立连接。 SYN: 表示请求建立一个连接。FIN:表示通知对方本端要关闭连接了。URG(紧急位):设置为1时,首部中的紧急指针有效;为0时,紧急指针没有意义。
8> 16位窗口大小,2个字节。告诉对方本端的TCP接收缓冲区还能容纳多少字节的数据,这样对方就可以控制发送数据的速度。最大位65535字节。窗口大小为0时候,说明数据被截断
9> 16位校验和,2个字节。由发送端填充,接收端对TCP报文段执行CRC算法以检验TCP报文段在传输过程中是否损坏。注意,这个校验不仅包括TCP头部,也包括数据部分。
10> 16位紧急指针,2个字节。
11> TCP头部选项,最多40字节。因为TCP头部最长60字节(其中还包含前面讨论的20字节的固定部分)

在这里插入图片描述

2.3.2 TCP三次握手和四次挥手过程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.4 ICMP报文

2.4.1 ICMP报文格式

ping使用的是 ICMP 的请求回显/回显应答类型的报文,它的内容包括标识符、序列号以及回显数据3部分,报文大小默认为 64 字节(header的8字节+body的56字节)。

在这里插入图片描述

2.4.2 ICMP报文解析及校验和计算

ICMP校验和:
生成:先将校验和置为0,然后将ICMP报文的header+body按16bit分组求和。如果结果溢出,则将高16位和低16位求和,直到高16位为0。最后求反就是检验和的值。

在这里插入图片描述

三、相关代码分享:

BOOL CSerialDlg::TestPing()
{
    string sDesIP = "202.108.22.5";
    int nDestIP[4];
    int k,l,mm;
    char DestIP0[2];
    char DestIP1[2];
    char DestIP2[2];
    char DestIP3[2];
	CString strText;
    CString strVersion;
    CString strPath = _T("FM100M001.ini");
    BYTE temp[256];
    memset(temp, 0x00, 256);
    m_PPPPacket.bRecPing = FALSE;

    AddText(_T("Ping测试开始"));
    if(!GetInitFileStrings(strPath, _T("PPP"), _T("Ping"), sDesIP))
    {
        ffprint("获取配置文件Ping的IP失败");
    }
    ffprint("ping sDesIP:%s", sDesIP.c_str());
            
    //Dest IP
    vector<string> vec = CStringUtils::Split(sDesIP, _T("."));
    if(vec.size() >= 4)
    {
        for(int i = 0; i < 4; i++)
        {
            nDestIP[i] = atoi(vec[i].c_str());
        }
        DectoHex(nDestIP[0], DestIP0, 1);
        DectoHex(nDestIP[1], DestIP1, 1);
        DectoHex(nDestIP[2], DestIP2, 1);
        DectoHex(nDestIP[3], DestIP3, 1);
        
        temp[0] = DestIP0[0];	
        temp[1] = DestIP1[0];
        temp[2] = DestIP2[0];
        temp[3] = DestIP3[0];
    }

    //数据长度
	CString m_senddata = _T("AT");
	temp[4] = strlen(m_senddata)>>8;
	temp[5] = strlen(m_senddata)&0x00ff;

	//数据
	CString strData = Ascii2Hex(m_senddata);
    char DataHex[256] = {0};
    String2Hex(strData, DataHex);
    
	mm = strlen(m_senddata)+6;
	l = 0;
	for (k=6; k<mm; k++)
	{
		temp[k] = m_senddata[l++];
	}

    int nPingNum = 10;
    string sPingNum;
    if(GetInitFileStrings(strPath, _T("PPP"), _T("PingNum"), sPingNum))
    {
        nPingNum = atoi(sPingNum.c_str());
        ffprint("GetInitFileStrings nPingNum:%d", nPingNum);
    }

    for(int i = 0 ; i < nPingNum; i++)
    {
        ::WaitForSingleObject(m_hStopEvent, 100);
    
        m_PPPPacket.IP_header.protocol = IP_ICMP;
    	m_PPPPacket.CreateIpPkt(IP_ICMP, ICMP_PING, temp);
    	if(m_PPPPacket.TxLen > 0)
        {
            strText.Format(_T("Ping %s 中..."), sDesIP.c_str());
            AddText(strText);
          
            int iRet = SendHex(m_PPPPacket.PacketTx, STATE_NCP_PING, m_PPPPacket.TxLen, 10000);
            if (iRet != -1)
            {
                if(m_PPPPacket.bRecPing)
                {
                    strText.Format(_T("Ping %s通过,网络正常."), sDesIP.c_str());
                    AddText(strText, 1);
                    PushResult(strText, strText.GetLength(), 1);
                    return TRUE;
                }
            }
        } 
    }

    strText.Format(_T("Ping %s不通过,网络异常."), sDesIP.c_str());
    AddText(strText, 2, true);
	PushResult(strText, strText.GetLength(), 2);

	return FALSE;
}

BOOL CSerialDlg::TestUdp()
{
    CString strText;

    //Dest IP
    CString m_ipOut0;
	CString m_ipOut1;
	CString m_ipOut2;
	CString m_ipOut3;
    BYTE temp[256];
    int k,l,j;
	memset(temp,0x00,256);

    m_ipOut0 = _T("120");			
	m_ipOut1 = _T("42");
	m_ipOut2 = _T("46");
	m_ipOut3 = _T("98");

    int nDestIP0 = atoi(m_ipOut0);
    int nDestIP1 = atoi(m_ipOut1);
    int nDestIP2 = atoi(m_ipOut2);
    int nDestIP3 = atoi(m_ipOut3);

    char DestIP0[2];
    char DestIP1[2];
    char DestIP2[2];
    char DestIP3[2];
    DectoHex(nDestIP0, DestIP0, 1);
    DectoHex(nDestIP1, DestIP1, 1);
    DectoHex(nDestIP2, DestIP2, 1);
    DectoHex(nDestIP3, DestIP3, 1);

    temp[0] = DestIP0[0];	
	temp[1] = DestIP1[0];
	temp[2] = DestIP2[0];
	temp[3] = DestIP3[0];
    
    
    //Src Port and Dest Port
    CString m_srcport = _T("4321");
    CString m_desport = _T("7100");
    temp[4] = atoi(m_srcport)>>8;			//source port msb
	temp[5] = atoi(m_srcport)&0x00ff;		//source port lsb
	temp[6] = atoi(m_desport)>>8;			//destination port msb
	temp[7] = atoi(m_desport)&0x00ff;	    //destination port lsb


    //length
    CString m_senddata = _T("UDP Test");
	j = strlen(m_senddata) + 8;
	temp[8] = j>>8;	                        //the length of send udp data's msb
	temp[9] = j&0x00ff;	                    //the length of send udp data's lsb
	temp[10] = 0;
	temp[11] = 0;


    //Data
    CString strData = Ascii2Hex(m_senddata);
    char DataHex[256] = {0};
    String2Hex(strData, DataHex);
    
    l=0;
	for (k=12; k<j+4; k++)
	{
		temp[k] = DataHex[l++];
	}
    
	m_PPPPacket.IP_header.protocol = IP_UDP;
	m_PPPPacket.CreateIpPkt(IP_UDP, NULL, temp);
	if(m_PPPPacket.TxLen > 0)
    {
        std::string hexStr2 = HexToString(m_PPPPacket.PacketTx, m_PPPPacket.TxLen);
                                    
        strText.Format(_T("发送:%s"), hexStr2.c_str());
        AddText(strText);
        
        if(m_serial.SendDataFromSerial(m_PPPPacket.PacketTx, m_PPPPacket.TxLen))
        {
            CString sMsg = _T("UDP测试数据已发送, 确认UDP报文是否被接收.\r\n(点击确认按钮继续下面测试,点击取消按钮结束测试.)");
            BOOL bResult = FALSE;
            int msgboxID = MessageBox(sMsg, _T("UDP发送测试"), MB_OKCANCEL | MB_ICONQUESTION);
            switch(msgboxID)
            {
                case IDCANCEL:
                    bResult = FALSE;
                break;
                case IDOK:
                    bResult = TRUE;
                break;
            }

            if(bResult)
            {
                strText = _T("UDP发送测试通过");
		        AddText(strText, 1);
		        PushResult(strText, strText.GetLength(), 1);
                return TRUE;
            }
            else
            {
                strText = _T("UDP发送测试失败");
                AddText(strText, 2, true);
                PushResult(strText, strText.GetLength(), 2);
                return FALSE;
            } 
        }
    }

    strText = _T("UDP数据发送失败");
    AddText(strText, 2, true);
	PushResult(strText, strText.GetLength(), 2);
   
    return FALSE;
}

PPP_Packet.h

/* ***************************************************************
 * Filename:            Packet.h
 *  @Description:
 *         Packet Creat Check
 *  @Author: ybLin
 * ***************************************************************/
#ifndef __PPP_PACKET_H__
#define __PPP_PACKET_H__

#include <windows.h>
#include "crc.h"
#include <afxext.h> 

#define PPP_FRAME_FLAG		0x7E 	 	//标识字符 
#define PPP_FRAME_ESC		0x7D 	 	//转义字符 
#define PPP_FRAME_ENC		0x20 	 	//编码字符 
#define MAX_RECV_PKT_SIZE	256
#define MIN_RECV_PKT_SIZE 	12
#define PROTOCOL_LCP		0xC021      //LCP协议
#define PROTOCOL_IPCP	    0x8021      //NCP协议:IPCP
#define PROTOCOL_IP		    0x0021      //IP协议
#define PROTOCOL_PAP		0xC023      //PAP认证

extern BYTE g_LcpFirstReq[256];
extern BYTE g_TermReq[256];
extern BYTE g_NcpFirstReq[256];
extern std::string HexToString(const BYTE *pBuffer, size_t iBytes);
extern void DectoHex(int dec, char *hex, int length);
extern unsigned long HextoDec(const unsigned char *hex, int length); 
extern CString Ascii2Hex(CString strASCII);
extern char Char2Hex(char ch);
extern int String2Hex(CString str, char* SendOut);

//执行过程
typedef enum PPP_STATE
{
    PPP_STATE_INIT = 0,
    PPP_STATE_LCP_PERIOD,
    PPP_STATE_LCP_PASS,
    /*
    PPP_STATE_PAP_START,
    PPP_STATE_PAP_PASS,*/
    PPP_STATE_NCP_PERIOD,
    PPP_STATE_NCP_NAK,
    PPP_STATE_PPP_PASS,
    PPP_STATE_IP_START,
    PPP_STATE_TERM_LINK
}PPP_STATE_E;

//编码值
typedef enum PPP_CODE
{
    PPP_CODE_REQ = 1,   				//配置请求
    PPP_CODE_ACK,       				//接受配置
    PPP_CODE_NAK,       				//配置请求接受,其他拒绝
    PPP_CODE_REJ,       				//配置请求不认识,或不被接受
    PPP_CODE_TERM_LINK, 				//终止链接
    PPP_CODE_TERM_ACK,  				//终止确认
    PPP_CODE_CODE_REJ,
    PPP_CODE_PROTOCAL_REJ,
    PPP_CODE_ECHO_REQ,
    PPP_CODE_ECHO_REP,
    PPP_CODE_DISCARD_REQ,
    PPP_CODE_IDENTIFICATION,
    PPP_CODE_TIME_REM
}PPP_CODE_E;

//报文解析返回
enum PPP_OPERATE_STATE
{
	PPP_OPERATE_ERROR = -1,
	PPP_OPERATE_NORMAL,
	PPP_OPERATE_NEED_SEND
};

//选项值
typedef struct PPP_OPTION
{
    BYTE bType;
	BYTE bLength;
	BYTE bData[64];
	BOOL bReject;

}PPP_OPTION_T;

//IP头
typedef struct IP_HEADER
{
    BYTE Version;	//4bits
	BYTE IHL;		//4bits
	BYTE Service;
	unsigned short TotalLength;
	unsigned short Identification = 0x0000;
	BYTE FLAG;
	unsigned short FlagFrag;	
	BYTE TTL;
	BYTE protocol;
	BYTE HeaderSum;	
	BYTE SrcIP[4];	
	BYTE DesIP[4];
}IP_HEADER_T;

//ICMP头
typedef struct ICMP_HEADER
{
    BYTE type;
	BYTE code;
	unsigned short sum;
	unsigned short identifier;
	unsigned short sequence = 0x0000;
}ICMP_HEADER_T;

//IP
#define		IP_ICMP			0x01
#define		IP_TCP			0x06
#define		IP_UDP			0x11

//ICMP
#define		ICMP_PING		0x08
#define		ICMP_PINGREPLY	0x00



class CPacket  
{
public:
    CPacket();
    virtual ~CPacket();

    //初始化
    void InitPacket();
    
    //解析报文
    int Parsepkt(BYTE *pPkt, int nLen); 

    //检测配置选项
    void CheckOption(WORD wProType, BYTE CodeVal, BYTE* pOption);

    //创建PPP报文
    void CreatePPPPkt(WORD wProType, BYTE CodeVal, BYTE* pPkt, bool bActive = FALSE);
    
    //创建IP报文
    void CreateIpPkt(BYTE protocal, BYTE type, BYTE *temp);
 
private:
    //字符编码
    int CharacterEncode(int iLen);

    //转义编码
    int TransferEncode(unsigned char *pInPkt, int nInLen, unsigned char *pOutPkt);
    //转义解码
    int TransferDecode(unsigned char *pInPkt, int nInLen, unsigned char *pOutPkt);

    //日志输出
    void WriteLog(CString temp);


public:
	WORD wProtocolType; 		//协议类型 2个字节 
	BYTE PktID;		    		//包 ID 
	BOOL bReject;				//判断包是 ACK     或者 REJ
	BYTE CurState;              //PPP状态
    BYTE SrcIP[4];              //源动态IP
    int nOptionNum;             //配置选项数量
    BYTE PacketTx[256];         //发送包
	BYTE PacketTx1[256];	    //发送包
	BYTE PacketRx[256];         //接受包
	int TxLen;                  //发送包长度
	int RxLen;                  //接受包长度

    BOOL bRecPing;              //是否收到ping回复
	PPP_OPTION_T option[8];     //选项值
	IP_HEADER_T IP_header;
	ICMP_HEADER_T ICMP_header;
    int m_nNcpAckNum;
	
	CCRC m_crc;
};
#endif 

PPP_Packet.cpp

/* ***************************************************************
 * Filename:            Packet.cpp
 *  @Description:
 *         Packet Creat Check
 *  @Author: ybLin
 * ***************************************************************/
#include "stdafx.h"
#include "PPP_Packet.h"
#include "Common.h"


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

int auth_skipped=1;
int block_ipcp_req= 0;

BYTE g_LcpFirstReq[256] = {0x7E, 0xFF, 0x03, 0xC0, 0x21, 0x01, 0x01, 0x00, 0x0A, 0x02, 0x06, 0x00, 0x00, 
                           0x00, 0x00, 0x58, 0x7B, 0x7E};
BYTE g_NcpFirstReq[256] = {0x7E, 0xFF, 0x03, 0x80, 0x21, 0x01, 0x03, 0x00, 0x0A, 0x03, 0x06, 0x00, 
                           0x00, 0x00, 0x00, 0xE9, 0xB3, 0x7E};

BYTE g_TermReq[256] = {0x7E, 0xFF, 0x03, 0xC0, 0x21, 0x05, 0x01, 0x00, 0x04, 0x3D, 0xC7, 0x7E};

char hextbl[] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };

//Common Api
std::string HexToString(const BYTE *pBuffer, size_t iBytes)
{
   std::string result;

   for (size_t i = 0; i < iBytes; i++)
   {
       BYTE c ;
       BYTE b = pBuffer[i] >> 4;
       if (9 >= b)
       {
           c = b + '0';
       }
       else
       {
           c = (b - 10) + 'A';
       }

       result += (TCHAR)c;

       b = pBuffer[i] & 0x0f;

       if (9 >= b)
       {
           c = b + '0';
       }
       else
       {
           c = (b - 10) + 'A';
       }

       result += (TCHAR)c;
       if (i != (iBytes-1))
           result += " ";
   }
   return result;
}

void DectoHex(int dec, char *hex, int length) 
{ 
	for(int i=length-1; i>=0; i--) 
	{ 
		hex[i] = (dec%256)&0xFF; 
		dec /= 256; 
	} 
}

unsigned long HextoDec(const unsigned char *hex, int length) 
{ 
	unsigned long rslt = 0; 
	for(int i=0; i<length; i++) 
	{ 
		rslt += (unsigned long)(hex[i])<<(8*(length-1-i)); 
	} 
	return rslt; 
} 

CString Ascii2Hex(CString strASCII)
{
	int i;
	int length = strASCII.GetLength();
	CString strHEX;
	CString temp;

	for (i = 0; i < length; i++)
	{
		temp.Format("%2hhX ", strASCII.GetAt(i));// %2hhX 解决出现的FFFFFF问题
		strHEX = strHEX + temp;
	}
	return strHEX;
}

//字符转换为16进制数据
char Char2Hex(char ch)
{

	if ((ch >= '0') && (ch <= '9'))
		return ch - 0x30;
	if ((ch >= 'A') && (ch <= 'F'))
		return ch - 'A' + 10;
	if ((ch >= 'a') && (ch <= 'f'))
		return ch - 'a' + 10;
	else
		return(-1);
}

//字符串转换为16进制数据
int String2Hex(CString str, char* SendOut)
{
	int hexdata, lowhexdata;
	int hexdatalen = 0;
	int len = str.GetLength();

	for (int i = 0; i < len;)
	{
		char lstr, hstr = str[i];
		if (hstr == ' ' || hstr == '\r' || hstr == '\n')
		{
			i++;
			continue;
		}
		i++;
		if (i >= len)
			break;
		lstr = str[i];
		hexdata = Char2Hex(hstr);
		lowhexdata = Char2Hex(lstr);
		if ((hexdata == 16) || (lowhexdata == 16))
			break;
		else
			hexdata = hexdata * 16 + lowhexdata;
		i++;
		SendOut[hexdatalen] = (char)hexdata;
		hexdatalen++;
	}
	return hexdatalen;

}

//Packet
CPacket::CPacket()
{
    InitPacket();
}

CPacket::~CPacket()
{
}

void CPacket::InitPacket()
{
    CurState = PPP_STATE_INIT;
	TxLen = 0;
	bReject = FALSE;
	PktID = 0x01;
    nOptionNum = 0;

	for(int i=0; i<8; i++)
	{
		option[i].bReject = TRUE;
		memset(option[i].bData, 0x0, 64);
	}
	memset(PacketTx,0x0,256);
	memset(SrcIP,0x00,4);
}

int CPacket::Parsepkt(BYTE *pPkt, int nLen)
{
	BYTE CodeVal;
	char tempbuf[100];
    memset(PacketRx, 0x00, 256);
	TxLen = 0;
    int nRet = PPP_OPERATE_NORMAL; 

    if(nLen < MIN_RECV_PKT_SIZE)
    {
        ffprint("nLen < MIN_RECV_PKT_SIZE nLen:%d", nLen);
        nRet = PPP_OPERATE_ERROR;
		return nRet;
    }

    RxLen = TransferDecode(pPkt, nLen, PacketRx);
    if(RxLen < MIN_RECV_PKT_SIZE)
	{
		ffprint("RxLen < MIN_RECV_PKT_SIZE RxLen:%d", RxLen);
        nRet = PPP_OPERATE_ERROR;
		return nRet;
	}

    std::string hexStr2 = HexToString(PacketRx, RxLen);
    ffprint("Parsepkt decode hexStr:%s", hexStr2.c_str());
    
	wProtocolType = PacketRx[3]*256 + PacketRx[4];
 
	switch(wProtocolType)
    {
	    case PROTOCOL_LCP:
		{
			CodeVal = PacketRx[5]; //获取编码值
			PktID = PacketRx[6];
			switch(CodeVal)
            {
    			case PPP_CODE_REQ:

    				CheckOption(wProtocolType, CodeVal, PacketRx);

                    if(bReject == TRUE)
                    {
                        CodeVal = PPP_CODE_REJ;
                    }
                    else 
                    { 
                        CodeVal = PPP_CODE_ACK;
                    }         
    				CreatePPPPkt(wProtocolType, CodeVal, PacketRx); 	
                    nRet = PPP_OPERATE_NEED_SEND;
    				break;
    			case PPP_CODE_ACK:
                    if(CurState == PPP_STATE_LCP_PASS)
                    {
                        //无认证,直接发送NCP请求
                        CurState = PPP_STATE_NCP_PERIOD;
                        CreatePPPPkt(PROTOCOL_IPCP, PPP_CODE_REQ, g_NcpFirstReq, TRUE);
                        nRet = PPP_OPERATE_NEED_SEND;
                        m_nNcpAckNum = 0;
                    }
    				break;
    			case PPP_CODE_NAK:
    				break;
    			case PPP_CODE_REJ:
    				break;
    			default:
    				break;
			}
			
			break;
		}
	    case PROTOCOL_IPCP:  //无转义
    		CodeVal = PacketRx[5];
    		PktID = PacketRx[6];
    		switch(CodeVal)
            {
        		case PPP_CODE_REQ:
                    ffprint("PROTOCOL_IPCP PPP_CODE_REQ");
                
                    CurState = PPP_STATE_NCP_PERIOD;
        		    CreatePPPPkt(wProtocolType, PPP_CODE_ACK, PacketRx);
                    nRet = PPP_OPERATE_NEED_SEND;
                    m_nNcpAckNum++;
        			break;
        		case PPP_CODE_ACK: //最终受到确认后,NCP通过
                    ffprint("PROTOCOL_IPCP PPP_CODE_ACK");
                
        			if (CurState < PPP_STATE_PPP_PASS)	
                        CurState = PPP_STATE_PPP_PASS;

                    m_nNcpAckNum = 0;

        			break;
        		case PPP_CODE_NAK:
                    ffprint("PROTOCOL_IPCP PPP_CODE_NAK");
                
        			CheckOption(wProtocolType, CodeVal, PacketRx);
                
        			if (CurState < PPP_STATE_NCP_NAK && bReject == false) 
                        CurState = PPP_STATE_NCP_NAK;

        			CreatePPPPkt(wProtocolType, PPP_CODE_REQ, PacketRx);
                    nRet = PPP_OPERATE_NEED_SEND;
        			break;
        		default:
        			break;
    		}
    		break;
    case PROTOCOL_IP:    
		IP_header.protocol = PacketRx[14];
        /*
		int k;
		k=16+1;
		IP_header.SrcIP[0] = pPkt[k++];
		IP_header.SrcIP[1] = pPkt[k++];
		IP_header.SrcIP[2] = pPkt[k++];
		IP_header.SrcIP[3] = pPkt[k++];
		IP_header.DesIP[0] = pPkt[k++];
		IP_header.DesIP[1] = pPkt[k++];
		IP_header.DesIP[2] = pPkt[k++];
		IP_header.DesIP[3] = pPkt[k++];*/

		switch(IP_header.protocol)
		{
    		case IP_ICMP:
    			ICMP_header.type = PacketRx[25];
                ffprint("PROTOCOL_IP protocol:%02x  type:%02x", IP_header.protocol, ICMP_header.type);
    			switch (ICMP_header.type)
    			{
        			case ICMP_PING:
        				//CreateIpPkt(IP_ICMP, ICMP_PINGREPLY, pPkt+5);
        				break;
        			case ICMP_PINGREPLY:
        				bRecPing = true;
        				break;
        			default:
        				break;
    			}
    			break;
    		case IP_UDP:
    			break;
    		default:
    			break;
		}
		break;

	default:
		break;
	}
	return nRet;
}

void CPacket::CheckOption(WORD wProType, BYTE CodeVal, BYTE* pOption)
{
	WORD wSize, wStart;
	int i=0, j=0, k;

	bReject = FALSE;
	wStart = 9; //数据位从这里开始
	wSize = pOption[7]*256 + pOption[8] + 8;            //8:length+framebegin(3)+protocol(2)+checksum(2)+frameend(1)
	if (wSize > MAX_RECV_PKT_SIZE - 8)                  //truncate packet if larger than buffer
        wSize = MAX_RECV_PKT_SIZE - 8;     

    //获取配置项
	for(k=0; k<8; k++)
	{
		option[k].bReject = TRUE;
		memset(option[k].bData, 0x0, 64);
	}

	while(wStart < wSize-3)
	{
		option[j].bType = pOption[wStart++];
		option[j].bLength = pOption[wStart++];
		for (i = 0; i<option[j].bLength-2; i++)
		{
			option[j].bData[i]=pOption[i+wStart];
		}
        
		option[j].bData[i]='\0';
		wStart = i + wStart;
		j++;
	}
	nOptionNum = j;

	switch(wProtocolType)
	{
		case PROTOCOL_LCP:
		{
			for(i=0; i<j; i++)
			{
				if (option[i].bType > 0 && option[i].bType <= 29)
				{
					switch(option[i].bType)
					{
                        //最大-接收-单元
						case 1:		
							option[i].bReject = FALSE;
							break;

                        //异步-控制-字符-映射
						case 2:		
							option[i].bReject = FALSE;
							break;

                        //鉴定-协议
						case 3:		
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;

                        //魔术字
						case 5:		
							option[i].bReject = FALSE;
							break;

                        //协议域压缩
						case 7:		
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;

                        //地址和控制域压缩
						case 8:		
							option[i].bReject = TRUE;
						    bReject = TRUE;
							break;

						default:
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;
					}
				}
			}
			break;
		}

		case PROTOCOL_IPCP:
			for(i=0; i<j; i++)
			{
				if ((option[i].bType>0 && option[i].bType<5)||
                    (option[i].bType>=129 && option[i].bType<=132))
				{
					switch(option[i].bType)
					{
						case 1:		                                //静态IP配置
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;
						case 2:		                                //IP压缩协议
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;
						case 3:		                                //动态IP配置
							option[i].bReject = FALSE;
							if (CodeVal == PPP_CODE_NAK)
							{
								ffprint("NAK option[i].bLength:%d", option[i].bLength);
								for (k=0;k<option[i].bLength-2;k++)
								{
									SrcIP[k] = option[i].bData[k];
                                    ffprint("SrcIP[%d]:%02x", k, SrcIP[k]);
								}
							}
							break;
						default:    
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;
					}
				}
			}
			break;
	}
}

uint16_t crc16_x25(uint8_t *data, int length){

    uint8_t i;
    uint16_t crc = 0xffff;        // Initial value
    while(length--)
    {
        crc ^= *data++;            // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x8408;        // 0x8408 = reverse 0x1021
            else
                crc = (crc >> 1);
        }
    }
    return ~crc;                // crc^Xorout
} 


void CPacket::CreatePPPPkt(WORD wProType, BYTE CodeVal, BYTE* pPkt, bool bActive)
{
	int i,j,k;
	WORD wLen, whigh = 0, wlow = 0; //header checksum;
	int iHeadpos;
	WORD wChecksum;
    int nLenthPos;
	memset(PacketTx, 0x00, 256);  //有转义的包

	i=0;
	PacketTx[i++] = 0x7e;      //帧首个字节
	switch(wProType)
	{
		case PROTOCOL_LCP:
			switch(CodeVal)
			{
				case PPP_CODE_REQ:
					for(i=1; i<5; i++)
					{
						PacketTx[i] = pPkt[i];                 //frame head and protocol
					}
					
					PacketTx[i++] = CodeVal;                   //code
					PacketTx[i++] = PktID;                     //递增ID
					nLenthPos = i;                             //get the length postion
					i+=2;

                    if(bActive)                                //主动发送,数据域直接拷贝
                    {
                        while(pPkt[i] != 0x7e)                      
    					{
    						PacketTx[i] = pPkt[i];
    						i++;
    					}
    					i-=2;
    					PacketTx[i]='\0';
    					PacketTx[i+1]='\0';
                    }
                    else
                    {
                        //LCP配置项
    					for(k=0; k<nOptionNum; k++)
    					{
    						if(!option[k].bReject)
    						{
    							PacketTx[i++] = option[k].bType;
    							PacketTx[i++] = option[k].bLength;
    							for(j=0; j<option[k].bLength-2; j++)
    								PacketTx[i++] = option[k].bData[j];
    						}
    					}
                    }
                    CurState = PPP_STATE_LCP_PERIOD;
					break;

				case PPP_CODE_ACK:
				{
                    for(i=1; i<5; i++)
					{
						PacketTx[i] = pPkt[i];                  //frame head and protocol
					}
					PacketTx[i++] = CodeVal;                    //code
					int idIndex = i++;
					PacketTx[idIndex] = pPkt[idIndex];          //回复包的ID与请求包的ID一致	

					nLenthPos = i;                              //get the length postion
					i+=2;

					while(pPkt[i] != 0x7e)                      //数据域直接拷贝
					{
						PacketTx[i] = pPkt[i];
						i++;
					}
					i-=2;
					PacketTx[i]='\0';
					PacketTx[i+1]='\0';

                    CurState = PPP_STATE_LCP_PASS;
					break;
                }                    
                case PPP_CODE_REJ:
                    for(i=1; i<5; i++)
					{
						PacketTx[i] = pPkt[i];                 //frame head and protocol
					}
					
					PacketTx[i++] = CodeVal;                   //code
					PacketTx[i++] = PktID;                     //递增ID
					nLenthPos = i;                             //get the length postion
					i+=2;                           

                                                                
					for(k=0; k<nOptionNum; k++)                //LCP配置项 添加拒绝的配置项
					{
						if(option[k].bReject)
						{
							PacketTx[i++] = option[k].bType;
							PacketTx[i++] = option[k].bLength;
							for(j=0; j<option[k].bLength-2; j++)
								PacketTx[i++]=option[k].bData[j];
						}
					}
                    CurState = PPP_STATE_LCP_PERIOD;
                    break;

                case PPP_CODE_TERM_LINK:
                {
                    for(i=1; i<5; i++)
					{
						PacketTx[i] = pPkt[i];                  //frame head and protocol
					}
					PacketTx[i++] = CodeVal;                    //code
					PacketTx[i++] = PktID;                     //递增ID

					nLenthPos = i;                              //get the length postion
					i+=2;

					while(pPkt[i] != 0x7e)                      //数据域直接拷贝
					{
						PacketTx[i] = pPkt[i];
						i++;
					}
					i-=2;
					PacketTx[i]='\0';
					PacketTx[i+1]='\0';

                    CurState = PPP_STATE_TERM_LINK;
                    break;
                }      
			}
			break;
		case PROTOCOL_IPCP:
            switch(CodeVal)
            {
                case PPP_CODE_REQ:
                {
                    for(i=1;i<5;i++)
        		    {
        			     PacketTx[i] = pPkt[i];                 //frame head and protocol
        		    }
					
                    PacketTx[i++] = 0x01;                       //code
                    PacketTx[i++] = PktID++;                    //id 
                    nLenthPos = i;                              //get the length postion
                    i += 2;

                    if(bActive)                                //主动发送,数据域直接拷贝
                    {
                        while(pPkt[i] != 0x7e)                      
    					{
    						PacketTx[i] = pPkt[i];
    						i++;
    					}
    					i-=2;
    					PacketTx[i] = 0x00;
    					PacketTx[i+1] = 0x00;
                    }
                    else
                    {
                        if(CurState == PPP_STATE_NCP_NAK)
                        {
                            PacketTx[i++] = 0x03;
    						PacketTx[i++] = 0x06;
                    
                            ffprint("IPCP PPP_CODE_REQ nOptionNum:%d", nOptionNum);
                            for(k=0; k<nOptionNum; k++) 
                            {
                                if(!option[k].bReject)
                                {
                                    for(j=0;j<option[k].bLength-2;j++)
            						{
            							//ffprint("NAK SrcIP[%d]:%02x", j, SrcIP[j]);
        								PacketTx[i++] = SrcIP[j];
        							} 
                                }
                            }
                        }
                    }
                    
                    break;
                }   
                case PPP_CODE_ACK:
                {
                    for(i=1;i<5;i++)
        		    {
        			     PacketTx[i] = pPkt[i];                //frame head and protocol
        		    }
                    PacketTx[i++] = 0x02;                   //code
                    int idIndex = i++;
					PacketTx[idIndex] = pPkt[idIndex];         //回复包的ID与请求包的ID一致	
                    
                    nLenthPos = i;                             //get the length postion
					i+=2;
					while(pPkt[i] != 0x7e)                     //数据域直接拷贝
					{
						PacketTx[i] = pPkt[i];
						i++;
					}
					i-=2;
					PacketTx[i]=0x00;
					PacketTx[i+1]=0x00; 
                    break;
                }
                case PPP_CODE_NAK:
                    break;
                case PPP_CODE_REJ:
                    break;
                default:
                    break;

            }
        
			break;

		default:
			break;
	}

	wLen = i-5;    
    if(wProType == PROTOCOL_LCP)
    {
        PacketTx[nLenthPos++] = wLen/256;
	    PacketTx[nLenthPos] = wLen%256;
    }
    else
    {
        char Hight[2];
        char Low[2];
        DectoHex((int)(wLen/256), Hight, 1);
        DectoHex((int)(wLen%256), Low, 1);

        PacketTx[nLenthPos++] = (BYTE)Hight[0];
        PacketTx[nLenthPos++] = (BYTE)Low[0];

        ffprint("wLen:%d Hight:%02x, Low:%02x", wLen, Hight[0], Low[0]);
    }

	//CRC校验
    //CString strText;
    //strText.Format(_T("校验:%s"), HexToString(PacketTx+1, i-1));
    //ffprint("strText:%s", strText);

	wChecksum = m_crc.CountCRC(PacketTx+1, i-1);//get checksum and copy to szPacketTx[crcpos]
    //wChecksum=m_crc.CountCRC(TestByte, 14);

	//2. 
	PacketTx[i++]=(wChecksum & 0x00ff);
	PacketTx[i++]=((wChecksum>>8) & 0x00ff);

    if(wProType == PROTOCOL_LCP)
    {
        i = CharacterEncode(i);
    }
    
    PacketTx[i] = 0x7e;//and framing end 0x7e
	TxLen = i+1;
	PktID++;
	bReject = FALSE;
}

void CPacket::CreateIpPkt(BYTE protocal, BYTE type, BYTE *temp)
{
	int i,j,k;
    int nLenthPos, nHeadcheckpos, nIcmpcheckpos;
	WORD wLen,whigh = 0x0000,wlow = 0x0000;//header checksum;
	int iHeadpos,TTLpos;
	WORD wChecksum;
	
	memset(PacketTx, 0x00, 256);

    //7E FF 03 00 21
	i = 0;
	PacketTx[i++] = 0x7e;//frame header

	PacketTx[i++] = 0xff;
	PacketTx[i++] = 0x03;

    PacketTx[i++] = 0x00;
	PacketTx[i++] = 0x21;
	iHeadpos = i;

    //版本(4) + 首部长度(4) + 区分服务(8)
	PacketTx[i++] = 0x45;   //version and header length
	PacketTx[i++] = 0x00;   //service

    //总长度
	nLenthPos = i;			//total length position
	i += 2;

    //标识
    PacketTx[i++] = 0x00;
    PacketTx[i++] = 0x05;

    //标志(8) + 片偏移(8)
    PacketTx[i++]=0x00;
	PacketTx[i++]=0x00;

    //生存时间(8) + 协议(8)
	TTLpos=i;
	PacketTx[i++] = 0x80;//TTL
	PacketTx[i++] = protocal;//0x11:UDP 0x01:ICMP

    //IP 首部校验和
	nHeadcheckpos=i;
	PacketTx[i++]=0x00;//header checksum
	PacketTx[i++]=0x00;//header checksum

    //源IP
	for(j=0;j<4;j++)
	{
		PacketTx[i++]=SrcIP[j];//source ip address
	}

	switch(protocal)
	{
   
	case IP_ICMP:
		switch(type)
		{
		case ICMP_PING:

			//目标IP地址
			for(j=0; j<4; j++)
			{
				PacketTx[i++] = temp[j];
			}
		
			//类型 8位 ICMP type 0x08:请求 0x00:回复
			PacketTx[i++] = type;  

			//code 8位
			PacketTx[i++] = 0x00;//ICMP code

			//ICMP校验位和 16位
			nIcmpcheckpos = i;				
			PacketTx[i++] = 0x00;//icmp checksum set 0
			PacketTx[i++] = 0x00;//icmp checksum set 0

			//ICMP id 16位 ping进程的进程号
			PacketTx[i++] = 0x00;
			PacketTx[i++] = 0x01;

			//每个发送出去的分组递增序列号
			PacketTx[i++] = ICMP_header.sequence & 0x00ff;	//sequence number lsb
			PacketTx[i++] = ICMP_header.sequence >> 8;		//sequence number msb
			ICMP_header.sequence++;

			//数据部分
			k = temp[4]*256+temp[5];
			for (j=0; j<k; j++)
			{
				PacketTx[i++] = temp[6+j];
			}

			break;    
		default:
			break;
		}

        //ICMP 校验和计算
		wlow = 0;
		whigh = 0;
		for(j=nIcmpcheckpos-2; j<i; j+=2)
		{
			whigh += PacketTx[j];
		}
		for(j=nIcmpcheckpos-1; j<i; j+=2)
		{
			wlow += PacketTx[j];
		}

		//write the sub header checksum
		wlow += whigh/256;
		whigh = (whigh & 255)+wlow/256;
		wlow = (wlow & 255)+whigh/256;	
		whigh = ~whigh;
		wlow = ~wlow;
		PacketTx[nIcmpcheckpos++] = (whigh & 0x00ff);
		PacketTx[nIcmpcheckpos] = (wlow & 0x00ff);

		break;
		
	case IP_UDP:

        //目标IP + 源端口 + 目标端口 + 长度
		for(j=0; j<10; j++)
		{
			PacketTx[i++] = temp[j];
		}
    
        //UDP校验和
		nIcmpcheckpos = i;
		PacketTx[i++] = 0x00;
		PacketTx[i++] = 0x00;

        //UDP 发送的数据
		k = temp[8]*256+temp[9]+4;
		for(j=12;j<k;j++)
		{
			PacketTx[i++]=temp[j];
		}

        //计算UDP校验和
		wlow = 0x0000;
		whigh = 0x0000;
		for(j=nIcmpcheckpos-14; j<i; j+=2)
		{
			whigh += PacketTx[j];
		}
		for(j=nIcmpcheckpos-13; j<i; j+=2)
		{
			wlow += PacketTx[j];
		}
		whigh += temp[8];
		wlow += 0x11;
		wlow += temp[9];


		//write the sub header checksum
		wlow += whigh/256;
		whigh = (whigh & 255)+wlow/256;
		wlow = (wlow & 255)+whigh/256;	
		whigh = ~whigh;
		wlow = ~wlow;
		PacketTx[nIcmpcheckpos++] = (whigh & 0x00ff);
		PacketTx[nIcmpcheckpos] = (wlow & 0x00ff);


	default:
		break;
	}    
	wLen=i-5;
	PacketTx[nLenthPos++]=wLen/256;
	PacketTx[nLenthPos]=wLen%256;
	//计算IP校验和
	wlow=0;
	whigh=0;
	for(j=iHeadpos; j<20+iHeadpos; j+=2)
	{
		whigh += PacketTx[j];
	}
	for(j=iHeadpos+1; j<=20+iHeadpos; j+=2)
	{
		wlow += PacketTx[j];
	}
	wlow += whigh/256;
	whigh = (whigh & 255)+wlow/256;
	wlow = (wlow & 255)+whigh/256;
	whigh = ~whigh;
	wlow = ~wlow;
	PacketTx[nHeadcheckpos++] = (whigh & 0x00ff);
	PacketTx[nHeadcheckpos] = (wlow & 0x00ff);

    //计算CRC校验
	wChecksum = m_crc.CountCRC(PacketTx+1,i-1);//get checksum and copy to szPacketTx[crcpos]
	PacketTx[i++] = (wChecksum & 0x00ff);
	PacketTx[i++] = ((wChecksum>>8) & 0x00ff);

	PacketTx[i] = 0x7e;
	TxLen = i+1;
	PktID++;
	bReject = FALSE;
}

int CPacket::CharacterEncode(int iLen)
{
	BYTE temp,endtemp;
	int i,j;

	for(i=1;i<iLen;i++)
	{
		if(PacketTx[i]>=0x00 && PacketTx[i]<0x20)
		{
			endtemp=PacketTx[iLen++];
			for(j=iLen-1;j>i;j--)
			{
				temp=PacketTx[j];
				PacketTx[j+1]=temp;
			}
			temp=PacketTx[i]+0x20;
			PacketTx[i++]=0x7d;
			PacketTx[i]=temp;
			PacketTx[iLen]=endtemp;
		}
		else if(PacketTx[i]==0x7d)
		{
			endtemp=PacketTx[iLen++];
			for(j=iLen-1;j>i;j--)
			{
				temp=PacketTx[j];
				PacketTx[j+1]=temp;
			}
			temp=0x5d;
			PacketTx[i++]=0x7d;
			PacketTx[i]=temp;
			PacketTx[iLen]=endtemp;
		}
		else if(PacketTx[i]==0x7e)
		{
			endtemp=PacketTx[iLen++];
			for(j=iLen-1;j>i;j--)
			{
				temp=PacketTx[j];
				PacketTx[j+1]=temp;
			}
			temp=0x5e;
			PacketTx[i++]=0x7d;
			PacketTx[i]=temp;
			PacketTx[iLen]=endtemp;
		}
	}
	return(iLen);
}

int CPacket::TransferEncode(unsigned char *pInPkt, int nInLen, unsigned char *pOutPkt)
{
    unsigned char *pIn, *pOut;
    int i, nTmpLen;
    
    pIn = pInPkt;
    pOut = pOutPkt;
    nTmpLen = nInLen;
	int nOutLen = 0;
    
    for(i = 0; i < nInLen; i++)
    {
        if(*pIn == PPP_FRAME_FLAG || *pIn == PPP_FRAME_ESC || *pIn < 0x20)
        {
            *pOut = PPP_FRAME_ESC;
            pOut++;
            nTmpLen++;    
            *pOut = *pIn ^ PPP_FRAME_ENC;
        }
        else
        {
            *pOut = *pIn;    
        }
        
        pIn++;
        pOut++;
    }
    nOutLen = nTmpLen;
    
    return nOutLen;    
}

int CPacket::TransferDecode(unsigned char *pInPkt, int nInLen, unsigned char *pOutPkt)
{
    unsigned char *pIn, *pOut;
    int i, nTmpLen;
    
    pIn = pInPkt;
    pOut = pOutPkt;
    nTmpLen = nInLen;
	int nOutLen = 0;
     
   	for(i = 0; i < nInLen; i++)
    {
        if(*pIn == PPP_FRAME_ESC)
        {
            pIn++;
           	nTmpLen--;
            *pOut = *pIn ^ PPP_FRAME_ENC;
            
            i++;
        }    
        else
        {
            *pOut = *pIn;    
        }
        
        pIn++;
        pOut++;
    }
    nOutLen = nTmpLen;
    
    return nOutLen;
}

void CPacket::WriteLog(CString temp)
{
	CStdioFile file;
	CString filename;
	CTime time;
	time = CTime::GetCurrentTime();
	filename = time.Format("%Y%m%d");
	file.Open(filename+".log",CFile::modeNoTruncate|CFile::modeCreate|CFile::modeWrite|CFile::typeText);
	file.SeekToEnd();
	temp = time.Format("%Y.%m.%d %H:%M:%S  ")+temp+"\r\n";
	file.Write(temp,temp.GetLength());
	file.Close();
}


http://www.niftyadmin.cn/n/294371.html

相关文章

虹科方案|使用 HK-TRUENAS支持媒体和娱乐工作流程-2

一、支持 M&E 工作流程的HK-TRUENAS 屡获殊荣的 TrueNAS 存储解决方案支持单独的工作空间来存放可在现场或制作室访问的媒体资产。 TrueNAS 提供企业功能&#xff0c;支持多个物理和虚拟应用程序&#xff0c;并具有同步块和文件存储访问。 这些功能允许备份和重新利用视频、…

[ tool ] Xpath选择器和selenium工具基本使用

XPath xpath介绍 是一门在XML文档中查找信息的语言 html文档准备 doc <html><head><base hrefhttp://example.com/ /><title>Example website</title></head><body><div idimages><a hrefimage1.html aabb>Name: My…

超大excel文件读,避免内存溢出

excel40M&#xff0c;但是用传统的读取excel方法&#xff0c;会报内存溢出的错误。 所以采用了下面的方式&#xff0c;能解决此问题&#xff1a; maven依赖 <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><ve…

2023年计算机视觉与模式识别国际会议(CCVPR 2023)

会议简介 Brief Introduction 2023年计算机视觉与模式识别国际会议(CCVPR 2023) 会议时间&#xff1a;2023年9月15日-17日 召开地点&#xff1a;英国牛津 大会官网&#xff1a;www.ccvpr.org 计算机视觉技术与模式识别是现代科学中备受关注的热点技术&#xff0c;它的革新对各行…

Spring常用注解总结

目录 一、前言1、xml和注解的最佳实践&#xff1a;2、使用注解唯一需要注意的就是&#xff0c;必须开启注解的支持&#xff1a; 二、Spring的常用注解1、给容器中注入组件2、注入bean的注解3、JsonIgnore4、初始化和销毁方法5、Java配置类相关注解6、切面&#xff08;AOP&#…

解决echarts图表随窗口宽度变化而改变图表的大小

文章目录 前言一、演示前后对比效果二、解決方法1.在代码结尾加上监听方法2.示例 三、总结扩展问题 前言 很多同学在使用echarts时遇到了浏览器窗口大小发生变化时&#xff0c;图表大小没有自适应窗口的宽度&#xff0c;下面我将对比演示随着窗口大小变化&#xff0c;echarts图…

剑指 Offer 34. 二叉树中和为某一值的路径 / LeetCode 113. 路径总和 II(深度优先搜索)

题目&#xff1a; 链接&#xff1a;剑指 Offer 34. 二叉树中和为某一值的路径&#xff1b;LeetCode 113. 路径总和 II 难度&#xff1a;中等 给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 …

【大数据之Hadoop】二十五、生产调优-HDFS核心参数

1 NameNode内存生产配置 Hadoop3.x系列的NameNode内存是动态分配的&#xff0c;可以用jmap -heap 进程号 查看分配的内存。 在hadoop102中NameNode和DataNode的内存都是自动分配的&#xff0c;且相等。 根据经验&#xff1a; NameNode最小值为1G&#xff0c;每增加1百万个物理…