网络协议深度解析:SSL、 TLS、HTTP和 DNS(C/C++代码实现)

在数字化时代,网络协议构成了互联网通信的基石。SSL、TLS、HTTP和DNS是其中最关键的几种,它们确保了我们的数据安全传输、网页的正确显示以及域名的正常解析。

要理解这些协议,首先需要了解网络分层模型。SSL和TLS位于传输层之上,用于加密数据;HTTP是应用层协议,负责网页内容的传输;而DNS则在应用层与传输层之间,它将人类可读的域名转换为机器可读的IP地址。

详细分析各个协议

DNS(域名系统)的主要作用

域名系统(DNS)是互联网的一项关键服务,它负责将用户可读的域名(如www.example.com)转换为网络设备可识别的IP地址(如192.0.2.1)。这个过程被称为域名解析。没有DNS,我们就需要记住复杂且难以记忆的数值序列来访问网站,这就大大降低了互联网的可用性。

DNS查询过程

当用户尝试访问一个网站时,以下是一个典型的DNS查询过程:

  1. 首先,用户的设备(比如电脑或手机)上的应用程序(通常是网页浏览器)会检查本地缓存,看看是否已经有对应域名的IP地址记录。如果有,它就直接使用该IP地址。

  2. 如果本地缓存中没有记录,设备会向配置的本地DNS服务器(通常由互联网服务提供商提供)发起解析请求。

  3. 本地DNS服务器收到请求后,会先检查自己的缓存。如果找到相应的记录,它会直接返回结果给请求者。

  4. 如果本地DNS服务器没有相关信息,它就会进行递归查询。在递归查询中,本地DNS服务器会代表请求者向其他DNS服务器发起查询请求,直到得到最终结果为止。

  5. 迭代查询则不同,它是一步接一步的过程,每一步只提供下一级查询的线索。在这种情况下,本地DNS服务器会告诉请求者下一个应该查询的DNS服务器的地址,请求者接着向这个新的地址发送请求,如此循环直至达到最终的权威名称服务器。

  6. 权威名称服务器负责管理特定域的DNS记录,它对所请求的域名拥有权威的信息。当查询到达这里,权威服务器会返回所请求的域名对应的IP地址记录。

  7. 一旦本地DNS服务器从权威名称服务器获取到所需的IP地址,它会将这个信息缓存起来以供后续使用,并将结果返回给原始请求者。

  8. 最后,原始请求者的设备收到解析出的IP地址,并使用该地址连接到目标网站。

从上面信息了解到,DNS通过一种分布式数据库的方式工作,它将域名解析任务分散到全球众多的DNS服务器上。这些服务器相互协作,通过递归或迭代查询,最终将用户友好的域名转换为网络上的设备能够理解的IP地址。

HTTP(超文本传输协议)的主要作用

超文本传输协议(HTTP)是用于传输网页文档的核心技术,它基于请求/响应模型工作。HTTP允许客户端(通常是Web浏览器)向服务器发送请求,并接收包含网页内容的响应。这个协议是无状态的,意味着每次通信后不会留下记录,除非使用某些技术如Cookie或会话标识来维持状态。

HTTP在应用层上运行,通常通过TCP/IP协议在网络中传输数据,但也可以在其他协议上运行,只要它们能提供类似可靠的流传输服务。

HTTP请求/响应模型

HTTP通信遵循一个非常直接的模型:一方(客户端)发送请求,另一方(服务器)返回响应。

  • 请求:由以下几部分组成:

    • 请求行:包含HTTP方法(如GET、POST)、请求的URL和HTTP协议版本。
    • 请求头:包含关于请求的附加信息,例如用户代理、接受的内容类型、语言等。
    • 空行:用以分隔请求头和请求体。
    • 请求体:对于一些请求方法(如POST、PUT),可能包含额外的数据。
  • 响应:同样由以下几部分组成:

    • 状态行:包含HTTP协议版本、状态码和状态消息。
    • 响应头:包含关于响应的附加信息,例如内容类型、内容长度、服务器信息等。
    • 空行:用以分隔响应头和响应体。
    • 响应体:实际返回给客户端的数据,比如HTML文档、图片或其他资源。

HTTP方法和状态码

  • 方法

    • GET:请求指定资源的表示形式。使用查询字符串可包含额外信息。
    • POST:提交要处理的数据,比如表单内容。
    • PUT:上传指定的资源替换目标资源。
    • DELETE:删除指定的资源。
    • HEAD:请求资源的头部信息,不返回实体主体。
    • OPTIONS:描述目标资源的通信选项。
    • CONNECT:建立网络隧道,转换为代理服务器。
    • 还有其他不常用的方法,如TRACE、PATCH等。
  • 状态码

    • 1xx(信息):请求已接收,继续处理。
    • 2xx(成功):请求正常处理完毕。例如,200 OK 表示请求成功,204 No Content 表示请求成功但没有内容返回。
    • 3xx(重定向):需要进一步操作以完成请求。例如,301 Moved Permanently 表示资源永久移动到新位置,304 Not Modified 表示资源未修改,可以使用缓存的副本。
    • 4xx(客户端错误):请求有语法错误或请求无法实现。例如,400 Bad Request 表示服务器无法理解请求的语法,404 Not Found 表示找不到请求的资源。
    • 5xx(服务器错误):服务器在处理请求的过程中发生了错误。例如,500 Internal Server Error 表示服务器内部错误,503 Service Unavailable 表示服务器目前无法处理请求。

总结来说,HTTP是Web通信的基础,它定义了客户端和服务器之间交换信息的格式和规则。了解HTTP的方法和状态码对于开发和维护网站和网络应用程序至关重要。

SSL/TLS(安全套接字层/传输层安全)

SSL和TLS用于加密客户端与服务器之间的通信,保障数据传输安全

SSL(Secure Sockets Layer)和TLS(Transport Layer Security)是网络安全中非常重要的技术。它们通过综合运用对称加密、非对称加密、消息认证码等密码学技术,为互联网上的数据传输提供安全保障。具体来说,SSL和TLS的主要作用包括:

  • 加密数据:防止敏感信息如登录凭证、交易细节等在传输过程中被未授权的第三方窃取;
  • 数据完整性:确保数据在传输过程中没有被篡改;
  • 身份验证:验证通信双方的身份,保证用户正在与真正的服务器进行交流。

SSL/TLS的握手过程涉及多个步骤,这个过程确定了加密参数,并在客户端与服务器之间建立了加密连接。具体如下:

  1. 客户端发起请求:客户端发送一个"client hello"消息到服务器,包含版本信息、加密套件列表、压缩算法和其他必要信息。此消息以明文形式发送。
  2. 服务器响应:服务器回应一个"server hello"消息,选择客户端提供的加密套件,并发送自己的数字证书及相关信息。
  3. 客户端验证:客户端接收服务器的证书,并对证书的有效性进行验证。如果需要,客户端也可能发送自己的证书给服务器进行双向验证。
  4. 密钥协商:双方根据协商的加密套件进行密钥交换。如果是使用RSA算法,服务器会用自己的私钥加密一个预备主秘钥,客户端用服务器的公钥解密得到主秘钥。
  5. 确立加密参数:使用从前面步骤得到的主秘钥,生成加密和MAC(消息认证码)密钥,这些密钥将用于后续的所有通信。
  6. 加密通信:双方确认无误后,开始使用协商好的加密参数进行加密通信。

了解HTTPS(HTTP over SSL/TLS)的结合方式

HTTPS,全称为HTTP Secure,也就是安全版的HTTP,它将HTTP协议与SSL/TLS协议结合起来,在互联网上提供加密的数据传输。具体结合方式如下:

  1. 应用层与传输层的安全封装:在标准的HTTP通信过程中,所有的数据传输都是明文形式的,这意味着数据可以被任何监听网络流量的人读取。而HTTPS通过在HTTP之上添加SSL/TLS协议,为数据提供了加密处理。这样即便是数据被截获,没有相应的密钥也无法解密数据内容。
  2. 保持HTTP的应用逻辑不变:在HTTPS的工作模式中,原有的HTTP请求和响应的处理逻辑并没有改变。只是在数据传输到TCP协议之前,先由SSL/TLS进行加密,确保了传输过程的安全性。这种分层的方法既保障了旧的HTTP应用无需修改即可升级到HTTPS,也符合了TCP/IP协议族的分层哲学。
  3. 使用安全的握手建立连接:当客户端与服务器进行HTTPS通信时,会首先建立一个SSL/TLS的握手,以确保双方的身份验证,并且确立加密参数和密钥。这个过程是整个加密通信的基础,并确保了后续所有传输的数据都能得到加密保护。
  4. 对外部资源的处理:现代网页通常包含多个外部资源,如图片、CSS和JavaScript文件等。在使用HTTPS时,即使是这些外部资源,浏览器也会分别建立安全的连接来获取它们,从而确保整个页面加载过程的数据安全。

所以,HTTPS的核心在于它在HTTP上增加了一层SSL/TLS协议,以实现数据的加密传输。这种机制不仅提高了数据传输的安全性,而且在很大程度上继承了原有HTTP协议的应用模型,使得从HTTP迁移到HTTPS的过程对于开发者和用户来说相对平滑。

网络协议深度解析:SSL、 TLS、HTTP和 DNS(C/C++代码实现)

#define PKT_PARSE_OK 0
#define PKT_PARSE_ERR -1

#define PKT_IPPROTO_ICMP                1       //ICMP
#define PKT_IPPROTO_TCP			  	    6		//TCP
#define PKT_IPPROTO_UDP					17		//UDP

#pragma pack(1)

typedef struct  {
	uint8_t		dest[6];
	uint8_t		src[6];
	uint16_t	type;
}PKT_ETH_HEADER_S;

///* IPv4 header */
typedef struct 
{
    uint8_t	ver_ihl;			/*Version (4 bits) + Internet header length (4 bits)*/
    uint8_t	tos;				/*Type of service*/
	uint16_t  tlen;				/*Total length*/ 
    uint16_t  identification;	/*Identification*/
    uint16_t  flags_fo;			/*Flags (3 bits) + Fragment offset (13 bits)*/
    uint8_t	ttl;				/*Time to live*/
    uint8_t	proto;				/*Protocol*/
    uint16_t  crc;				/*Header checksum*/
    uint32_t	saddr;			/*Source address*/
    uint32_t	daddr;			/*Destination address*/
    //uint32_t	op_pad;			/*Option + Padding*/
} PKT_IP_HEADER_S;
//
///* UDP header*/
typedef struct 
{
    uint16_t sport;				/*Source port*/
    uint16_t dport;				/*Destination port*/
    uint16_t len;					/*Datagram length*/
    uint16_t crc;					/*Checksum*/
} PKT_UDP_HEADER_S;
//
///* TCP header*/
typedef struct 
{
    uint16_t 	sport;				/*Source port*/
    uint16_t 	dport;				/*Destination port*/
    uint32_t	seq;				/*Sn number*/
    uint32_t	ack;				/*Ack number*/
    uint16_t	flags;
    uint16_t	win;				/*Window size*/
    uint16_t	sum;				/*Checksum*/
    uint16_t	urp;				/*Urgent pointer*/
} PKT_TCP_HEADER_S;

typedef struct 
{
    uint32_t          linkid;
    uint32_t          seq; //seq
    uint32_t		  ack;//ack
    uint32_t		  exp;//expire next seq
	uint16_t	      flags;
	uint16_t	      win;//Window size
	uint16_t	      crc;//Checksum
	uint16_t	      urp;//Urgent pointer
}PKT_TCP_S;

typedef struct 
{
    uint32_t      linkid;
	uint16_t      crc;	//Checksum
    uint32_t		len;    //udp len with head
    uint8_t*      data;
}PKT_UDP_S;

typedef union  
{
    PKT_TCP_S tcp;
    PKT_UDP_S udp;
}PKT_TRANS_LAYER_U;

typedef struct 
{
    uint32_t sip;       //源ip
    uint32_t dip;       //目的ip
    uint16_t sport;     //源port
    uint16_t dport;     //目的port
    uint8_t  proto;       //传输层协议PKT_IPPROTO_TCP,PKT_IPPROTO_UDP
    uint8_t *peth_pkt;      // 报文指针
    uint8_t *pnet_pkt;      //网络层指针,网络层起始
    uint8_t *ptrans_pkt;    //传输层指针,传输层起始
    uint8_t *papp_pkt;      //数据层指针,数据层起始
    uint8_t *pmpls_pkt;
	uint8_t *l2;
	uint8_t *l3;
	uint8_t *l4;
    uint16_t pkt_len;      //整个报文长度
    uint16_t ethh_len;      //2-2.5层头长度
    uint16_t net_len;      //ip数据长度,网络层+传输层+应用层
    uint16_t trans_len;    //传输层数据长度,传输层+应用层
    uint16_t app_len;      //应用层数据长度
    uint16_t mpls_len;      //应用层数据长度
    uint16_t eth_pack_num;   //2.5层封装层数
    uint8_t  vlan_flag;
	uint8_t  ipfrag_flag;  //ip分片标记,1分片
	uint8_t  mpls_flag;  
	uint8_t  ipv4_flag;
	uint8_t  ipv6_flag;
	uint8_t  icmp_flag;
	uint16_t app_proto; //应用层协议类型
    PKT_TRANS_LAYER_U trans_info; //tcp,udp信息 
}PKT_INFO_S;
#pragma pack()

#define IP_SIP(p)		ntohl(((PKT_IP_HEADER_S *)(p))->saddr)			/*源IP*/
#define IP_DIP(p)		ntohl(((PKT_IP_HEADER_S *)(p))->daddr)			/*目的IP*/
#define IP_HLEN(p)		((((PKT_IP_HEADER_S *)(p))->ver_ihl & 0x0F) << 2)	/*IP头长度*/
#define IP_PLEN(p)		ntohs(((PKT_IP_HEADER_S *)(p))->tlen)				/*IP包长度*/
#define IP_IDEN(p)      ntohs(((PKT_IP_HEADER_S *)(p))->identification)   /*IP包标识*/
#define IP_OFF(p)		((ntohs(((PKT_IP_HEADER_S *)(p))->flags_fo)&0x1FFF)<<3) 
#define IP_MF(p)		((((PKT_IP_HEADER_S *)(p))->flags_fo&0x20)>>5)		
#define UDP_SPORT(p)    ntohs(((PKT_UDP_HEADER_S *)(p))->sport)			/*Upd包源端口*/
#define UDP_DPORT(p)	ntohs(((PKT_UDP_HEADER_S *)(p))->dport)			/*Udp包目的端口*/
#define UDP_PLEN(p)		ntohs(((PKT_UDP_HEADER_S *)(p))->len)				/*Udp包的长度*/
#define UDP_HLEN        (uint16_t)8
#define TCP_SN(p)		ntohl(((PKT_TCP_HEADER_S*)(p))->seq)
#define TCP_ACK(p)		ntohl(((PKT_TCP_HEADER_S*)(p))->ack)
#define TCP_HLEN(p)		((((PKT_TCP_HEADER_S*)(p))->flags&0x00F0)>>2)
#define TCP_SPORT(p)	ntohs(((PKT_TCP_HEADER_S *)(p))->sport)			/*Tcp包源端口*/
#define TCP_DPORT(p)    ntohs(((PKT_TCP_HEADER_S *)(p))->dport)			/*Tcp包目的端口*/
#define TCP_WIN(p)      ntohs(((PKT_TCP_HEADER_S *)(p))->win)
#define TCP_SYN(p)		(((PKT_TCP_HEADER_S*)(p))->flags&0x0200)
#define TCP_FIN(p)		(((PKT_TCP_HEADER_S*)(p))->flags&0x0100)
#define TCP_RST(p)		(((PKT_TCP_HEADER_S*)(p))->flags&0x0400)
#define TCP_ACKF(p)      (((PKT_TCP_HEADER_S*)(p))->flags&0x1000)

struct http_header {
    char *name, *value;
};

struct http_message {
    char type;

    char *method, *url;
    char *protocol;
    char *status, *line;

    #define HTTP_HEADER_MAX 16
    struct http_header headers[HTTP_HEADER_MAX];

    char *body;

    char connection_close;
    char connection_keepalive;
    char gzip_supported;
};

typedef enum {
    DNS_UDP = 0,
    DNS_TCP,
}DNS_TRANS_TYPE;

typedef struct {
    DNS_TRANS_TYPE trans_type;
    int requestID;//请求标识
	int requestFlag;//请求标志
	char*  dns_queries_data;
    unsigned short dns_queries_len;
	char  DNSname[DNS_DATA_LENGTH+1];//DNS名称
	unsigned short requestType;//查询类型	
	unsigned short  requestClass;//查询类
}DNS_REQUEST_INFO;    

...

void CallBackPacket(char *data, int len)
{
...

    if (pkt_info.proto == PKT_IPPROTO_TCP && pkt_info.dport == 443)
    {
        //printf("-------------Https Packet Start------------- \n");

        char servername[128] = {0};
        int namelen = 0;
        err = ssl_clienthello_parser_servername(pkt_info.papp_pkt, pkt_info.app_len, servername, &namelen);
        if (err != 0)
        {
            //printf("    Not Find ServerName.\n");
        }
        else
        {
            if (namelen >= 128)
                return;

            servername[namelen] = 0;
            printf("[HTTPS] Find ServerName: %s, Sip:%d.%d.%d.%d Dip:%d.%d.%d.%d Sport:%d Dport:%d \n", servername,
                pkt_info.sip >> 24 & 0xff, pkt_info.sip >> 16 & 0xff, pkt_info.sip >> 8 & 0xff, pkt_info.sip & 0xff,
                pkt_info.dip>> 24 & 0xff, pkt_info.dip >> 16 & 0xff, pkt_info.dip >> 8 & 0xff, pkt_info.dip & 0xff,
                pkt_info.sport, pkt_info.dport);
        }
        
        //printf("-------------Https Packet E n d------------- \n");
    }
    else if (pkt_info.proto == PKT_IPPROTO_UDP && pkt_info.dport == 53)
    {
        DNS_REQUEST_INFO dns_req = {0};
        err = dns_parse(pkt_info.papp_pkt, pkt_info.app_len, &dns_req);
        if (err == 0)
        {
            printf("[DNS] DNS ServerName: %s, Sip:%d.%d.%d.%d Dip:%d.%d.%d.%d Sport:%d Dport:%d \n", dns_req.DNSname,
                pkt_info.sip >> 24 & 0xff, pkt_info.sip >> 16 & 0xff, pkt_info.sip >> 8 & 0xff, pkt_info.sip & 0xff,
                pkt_info.dip>> 24 & 0xff, pkt_info.dip >> 16 & 0xff, pkt_info.dip >> 8 & 0xff, pkt_info.dip & 0xff,
                pkt_info.sport, pkt_info.dport);
        }
       
    }
    else if (pkt_info.proto == PKT_IPPROTO_TCP && pkt_info.dport == 80)
    {
        struct http_message http_msg = {0};
        err = http_parser(pkt_info.papp_pkt, &http_msg, HTTP_REQUEST);
        if (err == 0)
        {
            int i = 0;
            char host[256] = {0};
            for (; i < 16; i++)
            {
                if (http_msg.headers[i].name)
                {
                    if (strncmp(http_msg.headers[i].name, "Host", 4) == 0)
                    {
                        strcpy(host, http_msg.headers[i].value);
                        int len = strlen(host);
                        if (host[len-1] == '\r')
                            host[len-1] = 0;
                        break;
                    }
                }
            }

            printf("[HTTP] Method:%s Host:%s URL: %s, Sip:%d.%d.%d.%d Dip:%d.%d.%d.%d Sport:%d Dport:%d \n", 
                http_msg.method,
                host,
                http_msg.url,
                pkt_info.sip >> 24 & 0xff, pkt_info.sip >> 16 & 0xff, pkt_info.sip >> 8 & 0xff, pkt_info.sip & 0xff,
                pkt_info.dip>> 24 & 0xff, pkt_info.dip >> 16 & 0xff, pkt_info.dip >> 8 & 0xff, pkt_info.dip & 0xff,
                pkt_info.sport, pkt_info.dport);            
        }
    }
...
    return;
}
...
int main(int argc, char *argv[])
{
...

    fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
    if(fd<0)
    {
        printf("socket create err %d. \n", fd);
        goto failed_2;
    }

//PACKET_VERSION和 SO_BINDTODEVICE可以省略
#if 1
    const int tpacket_version = TPACKET_V1;
    /* set tpacket hdr version. */
    ret = setsockopt(fd, SOL_PACKET, PACKET_VERSION, &tpacket_version, sizeof (int));
    if(ret<0)
    {
        printf("setsockopt packet version err %d. \n", ret);
        goto failed_2;
    }

    /* bind to device. */
    ret = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, intfName, strlen(intfName));
    if(ret<0)
    {
        printf("setsockopt bind device error %d . \n", ret);
        goto failed_2;
    }
#endif

    struct tpacket_req req;
#define PER_PACKET_SIZE 2048
    const int BUFFER_SIZE = 1024*1024*16; //16MB的缓冲区
    req.tp_block_size = 4096;
    req.tp_block_nr = BUFFER_SIZE/req.tp_block_size;
    req.tp_frame_size = PER_PACKET_SIZE;
    req.tp_frame_nr = BUFFER_SIZE/req.tp_frame_size;

    ret = setsockopt(fd, SOL_PACKET, PACKET_RX_RING, (void *)&req, sizeof(req));
    if(ret<0)
    {
        printf("setsockopt rx ring error %d . \n", ret);
        goto failed_2;
    }

    buff = (char *)mmap(0, BUFFER_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
    if(buff == MAP_FAILED)
    {
        printf("mmap err. \n");
        goto failed_2;
    }

    int nIndex=0, i=0;
    while(1)
    {
        //这里在poll前先检查是否已经有报文被捕获了
        struct tpacket_hdr* pHead = (struct tpacket_hdr*)(buff+ nIndex*PER_PACKET_SIZE);
        //如果frame的状态已经为TP_STATUS_USER了,说明已经在poll前已经有一个数据包被捕获了,如果poll后不再有数据包被捕获,那么这个报文不会被处理,这就是所谓的竞争情况。
        if(pHead->tp_status == TP_STATUS_USER)
            goto process_packet;

        //poll检测报文捕获
        struct pollfd pfd;
        pfd.fd = fd;
        //pfd.events = POLLIN|POLLRDNORM|POLLERR;
        pfd.events = POLLIN;
        pfd.revents = 0;
        ret = poll(&pfd, 1, -1);
        if(ret<0)
        {
            perror("poll");
            goto failed_1;
        }

process_packet:
        //尽力的去处理环形缓冲区中的数据frame,直到没有数据frame了
        for(i=0; i<req.tp_frame_nr; i++)
        {
            struct tpacket_hdr* pHead = (struct tpacket_hdr*)(buff+ nIndex*PER_PACKET_SIZE);

            //XXX: 由于frame都在一个环形缓冲区中,因此如果下一个frame中没有数据了,后面的frame也就没有frame了
            if(pHead->tp_status == TP_STATUS_KERNEL)
                break;

            //处理数据frame
            CallBackPacket((char*)pHead+pHead->tp_mac, pHead->tp_len);
            //char* mac = (char*)pHead+pHead->tp_mac;
            //printf("GetPacket,Len:%d,Mac:%2x-%2x-%2x-%2x-%2x-%2x\n", pHead->tp_len,
            //    mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);

            //重新设置frame的状态为TP_STATUS_KERNEL
            pHead->tp_len = 0;
            pHead->tp_status = TP_STATUS_KERNEL;

            //更新环形缓冲区的索引,指向下一个frame
            nIndex++;
            nIndex%=req.tp_frame_nr;
        }

    }
...
}

Makefile

CC = gcc
CFLAGS = -Wall -g
LIBS = -lpthread

all: main

main: main.o dns_parser.o http_parser.o packet_handle.o pkt_parse.o ssl_parser.o
	$(CC) $(CFLAGS) -o main main.o dns_parser.o http_parser.o packet_handle.o pkt_parse.o ssl_parser.o $(LIBS)

main.o: main.c
	$(CC) $(CFLAGS) -c main.c

dns_parser.o: dns_parser.c
	$(CC) $(CFLAGS) -c dns_parser.c

http_parser.o: http_parser.c
	$(CC) $(CFLAGS) -c http_parser.c

packet_handle.o: packet_handle.c
	$(CC) $(CFLAGS) -c packet_handle.c

pkt_parse.o: pkt_parse.c
	$(CC) $(CFLAGS) -c pkt_parse.c

ssl_parser.o: ssl_parser.c
	$(CC) $(CFLAGS) -c ssl_parser.c

clean:
	rm -f *.o main

运行结果:
If you need the complete source code, please add the WeChat number (c17865354792)

使用套接字接收网络数据包的示例。它创建了原始套接字,并将其绑定到指定的网络接口上。然后,它使用mmap()函数将一个环形缓冲区映射到内存中,以便存储捕获的数据包。接下来,它使用poll()函数检测是否有新的数据包到达,如果有,则处理这些数据包。在处理数据包时,它会调用CallBackPacket()函数处理数据包

总结

SSL(安全套接层)和TLS(传输层安全)是用于在互联网通信中提供安全和数据完整性的协议。它们位于传输层之上,确保数据在传输过程中被加密,以防止未经授权的访问和篡改。

HTTP(超文本传输协议)是一种应用层协议,用于在互联网上传输网页和其他资源。它定义了客户端和服务器之间的通信规则,确保网页内容能够正确地传输和显示。

DNS(域名系统)是一种将人类可读的域名转换为机器可读的IP地址的系统。它位于应用层和传输层之间,当用户在浏览器中输入一个域名时,DNS会将其解析为对应的IP地址,以便计算机能够找到并连接到目标服务器。

We also undertake the development of program requirements here. If necessary, please follow the WeChat official account 【程序猿编码】and contact me

参考:RFC 1035、RFC 2246、RFC 7235

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/573730.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2000-2022年各区县农产品产量数据

2000-2022年县域农产品产量数据 1、时间&#xff1a;2000-2022年 2、指标&#xff1a;统计年度、县域名称、所属地级市、所属省份、地区编码ID、县域代码、产品种类或名称、单位、产量、 3、来源&#xff1a;统计局、县域统计年鉴、各区县政府官网 4、范围&#xff1a;具体…

网络编程——TCP的特性之自动重传/流量控制/拥塞控制,一篇说清楚

文章目录 1. ARQ自动重传协议1.1 停止等待ARQ1.2 连续ARQ1.3 总结 2. TCP的流量控制3. TCP的拥塞控制3.1 慢开始算法3.2 拥塞避免算法3.3 快重传算法3.4 快恢复算法 1. ARQ自动重传协议 自动重传请求&#xff08;Automatic Repeat-reQuest&#xff09;&#xff0c;通过使用确认…

创新与乐趣的融合 —— 探索我们独家录音变音芯片在学舌玩具领域的应用

一&#xff1a;概述 学舌玩具&#xff0c;又称作复读玩具或模仿玩具&#xff0c;是一类设计用来录制人声并重复播放的互动式玩具。这类玩具以其能够模仿人类语音的特性而受到小朋友和宠物主人的喜爱。这些玩具通常具有以下特点和功能&#xff1a; 1. 录音和播放功能&#xff…

【C++航海王:追寻罗杰的编程之路】C++11(二)

目录 C11(上) 1 -> STL中的一些变化 2 -> 右值引用和移动语义 2.1 -> 左值引用和右值引用 2.2 -> 左值引用与右值引用比较 2.3 -> 右值引用使用场景与意义 2.4 -> 右值引用引用左值及其更深入的使用场景分析 2.5 -> 完美转发 C11(上) 1 -> STL…

4 -25

1 100个英语单词两篇六级阅读 2 cf补题&#xff1b; 3 仿b站项目看源码 debug分析业务。 上了一天课&#xff0c;晚上去健身。 物理备课&#xff0c;周六去上课腻。 五一回来毛泽东思想期末考试&#xff0c;概率论期中考试。

轻松搭建MySQL 8.0:Ubuntu上的完美指南

欢迎来到我的博客&#xff0c;代码的世界里&#xff0c;每一行都是一个故事 轻松搭建MySQL 8.0&#xff1a;Ubuntu上的完美指南 前言脚本编写脚本实现部署过程参数成功页面 彩蛋坏蛋解决方法 前言 在数字化时代&#xff0c;数据就像是我们的宝藏&#xff0c;而MySQL数据库就是…

【Qt 学习笔记】Qt常用控件 | 输入类控件 | Text Edit的使用及说明

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 输入类控件 | Text Edit的使用及说明 文章编号&#xff…

【题解】牛客挑战赛 71 - A 和的期望

原题链接 https://ac.nowcoder.com/acm/problem/264714 思路分析 快速幂求逆元 费马小定理&#xff1a; a MOD − 1 ≡ 1 ( m o d M O D ) a^{\text{MOD}-1} \equiv 1 \pmod{MOD} aMOD−1≡1(modMOD)&#xff0c;可以转换为 a ⋅ a MOD − 2 ≡ 1 ( m o d M O D ) ① a \cd…

4.24总结

对部分代码进行了修改&#xff0c;将一些代码封装成方法&#xff0c;实现了头像功能&#xff0c;通过FileInputStream将本地的图片写入&#xff0c;再通过FileOutputStream拷贝到服务端的文件夹中&#xff0c;并将服务端的文件路径存入数据库中

Linear Blend Skinning (LBS)线性混合蒙皮

LBS是CG的基础概念之一。 Linear Blend Skinning: linearly blend the results of the vertex transformed rigidly with each bone. LBS&#xff1a;线性地混合顶点根据每个骨骼的刚性变形结果。 这个场景应用在哪里呢&#xff1f; 假如我们重建好一个人体&#xff0c;现在用…

水位监测识别摄像机

水位监测识别摄像机是一种利用人工智能技术进行水位监测的智能设备&#xff0c;其作用是监测水体的水位变化并识别潜在的水灾危险&#xff0c;以提供准确数据和及时预警&#xff0c;帮助保护人民生命财产安全。这种摄像机通过高清摄像头实时捕捉水体的图像&#xff0c;然后利用…

Coursera: An Introduction to American Law 学习笔记 Week 03: Property Law

An Introduction to American Law 本文是 https://www.coursera.org/programs/career-training-for-nevadans-k7yhc/learn/american-law 这门课的学习笔记。 文章目录 An Introduction to American LawInstructors Week 03: Property LawKey Property Law TermsSupplemental Re…

【yolo算法道路井盖检测】

yolo算法道路井盖检测 数据集和模型yolov8道路井盖-下水道井盖检测训练模型数据集pyqt界面yolov8道路井盖-下水道井盖检测训练模型数据集 算法原理 1. 数据集准备与增强 数据采集&#xff1a;使用行车记录仪或其他设备收集道路井盖的图像数据。数据标注&#xff1a;对收集到…

如何提交已暂存的更改到本地仓库?

文章目录 如何提交已暂存的更改到本地Git仓库&#xff1f;步骤1&#xff1a;确认并暂存更改步骤2&#xff1a;提交暂存的更改到本地仓库 如何提交已暂存的更改到本地Git仓库&#xff1f; 在Git版本控制系统中&#xff0c;当你对项目文件进行修改后&#xff0c;首先需要将这些更…

大学生在线考试|基于SprinBoot+vue的在线试题库系统系统(源码+数据库+文档)

大学生在线考试目录 基于SprinBootvue的在线试题库系统系统 一、前言 二、系统设计 三、系统功能设计 试卷管理 试题管理 考试管理 错题本 考试记录 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#…

valgrind,memcheck的使用

一&#xff0c;valgrind介绍 ​ valgrind是一个开源的&#xff0c;检测内存泄漏的工具&#xff0c;通常在linux下使用&#xff0c;除此之外&#xff0c;他还能检测内存管理错误&#xff0c;线程bug等错误。粗浅的来讲&#xff0c;valgrind由两部分构成&#xff0c;一部分用来模…

每日OJ题_BFS解决拓扑排序③_力扣LCR 114. 火星词典

目录 力扣LCR 114. 火星词典 解析代码 力扣LCR 114. 火星词典 LCR 114. 火星词典 难度 困难 现有一种使用英语字母的外星文语言&#xff0c;这门语言的字母顺序与英语顺序不同。 给定一个字符串列表 words &#xff0c;作为这门语言的词典&#xff0c;words 中的字符串已…

SpringBoot-无法从static上下文引用同非static方法

1.问题 说明&#xff1a;无法从static上下文引用同非static方法。 2.解决 说明&#xff1a;return后面的语句中&#xff0c;调用的是变量的方法&#xff0c;而不是类型的方法&#xff01;

Pytorch学习之路 - CNN

目录 理论预热 实践 构建卷积神经网络 卷积网络模块构建 实战&#xff1a;基于经典网络架构训练图像分类模型 数据预处理部分&#xff1a; 网络模块设置&#xff1a; 网络模型保存与测试 实践 制作好数据源&#xff1a; 图片 标签 展示下数据 加载models中提供的模…

CMake:相关概念与使用入门(一)

1、Cmake概述 Cmake是一个项目构建工具&#xff0c;并且是跨平台的。 关于项目构建我们所熟知的有Makefile&#xff0c;然后通过make命令进行项目的构建&#xff0c;并且大多数是IDE都继承了make&#xff0c;比如&#xff1a;VS的nmake&#xff0c;Linux下的GNU make、Qt的qma…