原始套接字

article/2025/10/20 20:48:13

一、原始套接字概述

协议栈的原始套接字从实现上可以分为“链路层原始套接字”和“网络层原始套接字”两大类。

链路层原始套接字可以直接用于接收和发送链路层的MAC帧,在发送时需要由调用者自行构造和封装MAC首部。而网络层原始套接字可以直接用于接收和发送IP层的报文数据,在发送时需要自行构造IP报文头(取决是否设置IP_HDRINCL选项)。

1.1  链路层原始套接字

链路层原始套接字调用socket()函数创建。第一个参数指定协议族类型为PF_PACKET,第二个参数type可以设置为SOCK_RAW或SOCK_DGRAM,第三个参数是协议类型(该参数只对报文接收有意义)。协议类型protocol不同取值的意义具体见表1所示:

socket(PF_PACKET, type, htons(protocol))

a)       参数type设置为SOCK_RAW时,套接字接收和发送的数据都是从MAC首部开始的。在发送时需要由调用者从MAC首部开始构造和封装报文数据。type设置为SOCK_RAW的情况应用是比较多的,因为某些项目会使用到自定义的二层报文类型。

socket(PF_PACKET, SOCK_RAW, htons(protocol))

b)      参数type设置为SOCK_DGRAM时,套接字接收到的数据报文会将MAC首部去掉。同时在发送时也不需要再手动构造MAC首部,只需要从IP首部(或ARP首部,取决于封装的报文类型)开始构造即可,而MAC首部的填充由内核实现的。若对于MAC首部不关心的场景,可以使用这种类型,这种用法用得比较少。

socket(PF_PACKET, SOCK_DGRAM, htons(protocol))

表1  protocol不同取值

表1  中protocol的取值中有两个值是比较特殊的。当protocol为ETH_P_ALL时,表示能够接收本机收到的所有二层报文(包括IP, ARP, 自定义二层报文等),同时这种类型套接字还能够将外发的报文再收回来。当protocol为0时,表示该套接字不能用于接收报文,只能用于发送。具体的实现细节在2.2节中会详细介绍。

1.2  网络层原始套接字

创建面向连接的TCP和创建面向无连接的UDP套接字,在接收和发送时只能操作数据部分,而不能对IP首部或TCP和UDP首部进行操作。如果想要操作IP首部或传输层协议首部,就需要调用如下socket()函数创建网络层原始套接字。第一个参数指定协议族的类型为PF_INET,第二个参数为SOCK_RAW,第三个参数protocol为协议类型(不同取值的意义见表2)。产品线有使用OSPF和RSVP等协议,需要使用这种类型的套接字。

socktet(PF_INET, SOCK_RAW, protocol)

a)       接收报文

网络层原始套接字接收到的报文数据是从IP首部开始的,即接收到的数据包含了IP首部, TCP/UDP/ICMP等首部, 以及数据部分。     

b)      发送报文

网络层原始套接字发送的报文数据,在默认情况下是从IP首部之后开始的,即需要由调用者自行构造和封装TCP/UDP等协议首部。这种套接字也提供了发送时从IP首部开始构造数据的功能,通过setsockopt()给套接字设置上IP_HDRINCL选项,就需要在发送时自行构造IP首部。

int val = 1;  setsockopt (sockfd, IPPROTO_IP, IP_HDRINCL, &val, sizeof(val));

表2  protocol不同取

表2中protocol取值为IPPROTO_RAW是比较特殊的,表示套接字不能用于接收,只能用于发送(且发送时需要从IP首部开始构造报文)。具体的实现细节在2.3节中会详细介绍。

二、原始套接字实现

本节主要首先介绍链路层和网络层原始套接字报文的收发总体流程,再分别对两类套接字的创建、接收、发送等具体实现细节进行介绍。

2.1  原始套接字报文收发流程

图1  原始套接字收发流程

 

 

 

 

 

 

如上图1所示为链路层和网络层原始套接字的收发总体流程。网卡驱动收到报文后在软中断上下文中由netif_receive_skb()处理,匹配是否有注册的链路层原始套接字,若匹配上就通过skb_clone()来克隆报文,并将报文交给相应的原始套接字。对于IP报文,在协议栈的ip_local_deliver_finish()函数中会匹配是否有注册的网络层原始套接字,若匹配上就通过skb_clone()克隆报文并交给相应的原始套接字来处理。

注意:这里只是将报文克隆一份交给原始套接字,而该报文还是会继续走后续的协议栈处理流程。

 

 

 

 

 

      链路层原始套接字的发送,直接由套接字层调用packet_sendmsg()函数,最终再调用网卡驱动的发送函数。网络层原始套接字的发送实现要相对复杂一些,由套接字层调用inet_sendmsg()->raw_sendmsg(),再经过路由和邻居子系统的处理后,最终调用网卡驱动的发送函数。若注册了ETH_P_ALL类型套接字,还需要将外发报文再收回去。

2.2  链路层原始套接字的实现

2.2.1  套接字创建

调用socket()函数创建套接字的流程如下,链路层原始套接字最终由packet_create()创建。

sys_socket()->sock_create()->__sock_create()->packet_create()

    当socket()函数的第三个参数protocol为非零的情况下,会调用dev_add_pack()将链路层套接字packet_sock的packet_type结构链到ptype_all链表或ptype_base链表中。   

void dev_add_pack(struct packet_type *pt)
{         ……        if (pt->type == htons(ETH_P_ALL)){               netdev_nit++;list_add_rcu(&pt->list, &ptype_all);         } else {                hash = ntohs(pt->type) & 15;                 list_add_rcu(&pt->list, &ptype_base[hash]);         } ……
}

  当protocol为ETH_P_ALL时,会将套接字加入到ptype_all链表中。如图2所示,这里创建了两个链路层原始套接字。

 

图2  ptype_all链表

 

 

 

 

 

当protocol为其它非0值时,会将套接字加入到ptype_base链表中。如图3所示,协议栈本身也需要注册packet_type结构,图中浅色的两个packet_type结构分别是IP协议和ARP协议注册的,其处理函数分别为ip_rcv()和arp_rcv()。图中另外3个深色的packet_type结构则是链路层原始套接字注册的,分别用于接收类型为ETH_P_IP、ETH_P_ARP和0x0810类型的报文。

 

 

图3  ptype_base链表

 

 

 

 

 

 

 

 

 

 

 

2.2.2  报文接收

网卡驱动程序接收到报文后,在软中断上下文由netif_receive_skb()处理。首先会逐个遍历ptype_all链表中的packet_type结构,若满足条件“(!ptype->dev || ptype->dev == skb->dev)”,即套接字未绑定或者套接字绑定网口与skb所在网口匹配,就增加报文引用计数并交给packet_rcv()函数处理(若使用PACKET_MMAP收包方式则由tpacket_rcv()函数处理)。

网卡驱动->netif_receive_skb()->deliver_skb()->packet_rcv()/tpacket_rcv()

    以非PACKET_MMAP收包方式为例进行说明,packet_rcv()函数中比较重要的代码片段如下。当报文skb到达packet_rcv()函数时,其skb->data所指的数据是不包含MAC首部的,所以对于type为非SOCK_DGRAM(即SOCK_RAW)类型,需要将skb->data指针前移,以便数据部分可以包含MAC首部。最后将skb放到套接字的接收队列sk->sk_receive_queue中,并唤醒用户态进程来读取套接字中的数据。
 

…… 
if (sk->sk_type != SOCK_DGRAM) //即SOCK_RAW类型         
skb_push(skb, skb->data - skb->mac.raw);…… 
__skb_queue_tail(&sk->sk_receive_queue, skb); 
->sk_data_ready(sk, skb->len); //唤醒进程读取数据……

PACKET_MMAP收包方式的实现有所不同,tpacket_rcv()函数将skb->data拷贝到与用户态mmap映射的共享内存中,最后唤醒用户态进程来读取数据。由于报文的内容已存放在内核空间和用户空间共享的缓冲区中,用户态可以直接读取以减少数据的拷贝,所以这种方式效率比较高。

    上面介绍了报文接收在软中断的处理流程。下面以非PACKET_MMAP收包方式为例,介绍用户态读取报文数据的流程。用户态recvmsg()最终调用skb_recv_datagram(),如果套接字接收队列sk->sk_receive_queue中有报文就取skb并返回。否则调用wait_for_packet()等待,直到内核软中断收到报文并唤醒用户态进程。

sys_recvmsg()->sock_recvmsg()->…->packet_recvmsg()->skb_recv_datagram()

2.2.3  报文发送

用户态调用sendto()或sendmsg()发送报文的内核态处理流程如下,由套接字层最终会调用到packet_sendmsg()。

sys_sendto()->sock_sendmsg()->__sock_sendmsg()->packet_sendmsg()->dev_queue_xmit()

    该函数比较重要的函数片段如下。首先进行参数检查及skb分配,再调用驱动程序的hard_header函数(对于以太网驱动是eth_header()函数)来构造报文的MAC头部,此时的skb->data是指向MAC首部的,且skb->len为MAC首部长度(即14)。对于创建时指定type为SOCK_RAW类型套接字,由于在发送时需要自行构造MAC头部,所以将skb->tail指针恢复到MAC首部开始的位置,并将skb->len设置为0(即不使用内核构造的MAC首部)。接着再调用memcpy_fromiovec()从skb->tail的位置开始拷贝报文数据,最终调用网卡驱动的发送函数将报文发送出去。

注:如果创建套接字时指定type为SOCK_DGRAM,则使用内核构造的MAC首部,用户态发送的数据中不含MAC头部数据。

… res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len); //构造MAC首部 
if (sock->type != SOCK_DGRAM) 
{         skb->tail = skb->data; //SOCK_RAW类型        skb->len = 0; 
} 
……err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); //拷贝报文数据…… 
err = dev_queue_xmit(skb); //发送报文 ……

2.2.4  其它

a)         套接字的绑定

链路层原始套接字可调用bind()函数进行绑定,让packet_type结构dev字段指向相应的net_device结构,即将套接字绑定到相应的网口上。如2.2.2节报文接收的描述,在接收时如果套接口有绑定就需要进一步确认当前skb->dev是否与绑定网口相匹配,只有匹配的才会将报文上送到相应的套接字。

sys_bind()->packet_bind()->packet_do_bind()

b)        套接字选项

以下是比较常用的套接字选项

PACKET_RX_RING:用于PACKET_MMAP收包方式设置接收环形队列

PACKET_STATISTICS:用于读取收包统计信息

c)       信息查看

链路层原始套接字的信息可通过/proc/net/packet进行查看。如下为图2和图3中创建的原始套接字的信息,可以查看到创建时指定的协议类型、是否绑定网口、已使用的接收缓存大小等信息。这些信息对于分析和定位问题有帮助。

cat /proc/net/packetsk RefCnt Type Proto Iface R Rmem User Inodeffff810007df8400 3 3 0810 0 1 0 0 1310ffff810007df8800 3 3 0806 0 1 0 0 1309ffff810007df8c00 3 3 0800 0 1 560 0 1308ffff810007df8000 3 3 0003 0 1 560 0 1307ffff810007df3800 3 3 0003 0 1 560 0 1306

2.3  网络层原始套接字的实现

2.3.1  套接字创建

如图4所示,在IPV4协议栈中一个传输层协议(如TCP,UDP,UDP-Lite等)对应一个inet_protosw结构,而inet_protosw结构中又包含了proto_ops结构和proto结构。网络子系统初始化时将所有的inet_protosw结构hash到全局的inetsw[]数组中。proto_ops结构实现的是从与协议无关的套接口层到协议相关的传输层的转接,而proto结构又将传输层映射到网络层。

图4  inetsw[]数组结构

调用socket()函数创建套接字的流程如下,网络层原始套接字最终由inet_create()创建。

sys_socket()->sock_create()->__sock_create()->inet_create()

    inet_create()函数除用于创建网络层原始套接字外,还用于创建TCP、UDP套接字。首先根据socket()函数的第二个参数(即SOCK_RAW)在inetsw[]数组中匹配到相应的inet_protosw结构。并将套接字结构的ops设置为inet_sockraw_ops,将套接字结构的sk_prot设置为raw_prot。然后对于SOCK_RAW类型套接字,还要将inet->num设置为协议类型,以便最后能调用proto结构的hash函数(即raw_v4_hash())。

…… sock->ops = answer->ops; //将socket结构的ops设置为
inet_sockraw_ops answer_prot = answer->prot; 
…… 
if (SOCK_RAW == sock->type) 
{ //SOCK_RAW类型的套接字,设置inet->num        inet->num = protocol;         if (IPPROTO_RAW == protocol) //protocol为IPPROTO_RAW的特殊处理,                inet->hdrincl = 1; 后续在报文发送时会再讲到 
}……
if (inet->num)
{        inet->sport = htons(inet->num);         sk->sk_prot->hash(sk); //调用raw_v4_hash()函数将套接字链到raw_v4_htable中 
} 
……

经过如上操作后,相应的套接字结构sock会通过raw_v4_hash()函数链到raw_v4_htable链表中,网络层原始套接字报文接收时需要使用到raw_v4_htable。如图5所示,共创建了3个网络层原始套接字,协议类型分别为IPPROTO_TCP、IPPROTO_ICMP和89。

图5  raw_v4_htable链表

 

 

2.3.2  报文接收

网卡驱动收到报文后在软中断上下文由netif_receive_skb()处理,对于IP报文且目的地址为本机的会由ip_rcv()最终调用ip_local_deliver_finish()函数。ip_local_deliver_finish()主要功能的代码片段如下,先根据报文的L4层协议类型hash值在图5中的raw_v4_htable表中查找是否有匹配的sock。如果有匹配的sock结构,就进一步调用raw_v4_input()处理网络层原始套接字。不管是否有原始套接字要处理,该报文都会走后续的协议栈处理流程。即会继续匹配inet_protos[]数组,根据L4层协议类型走TCP、UDP、ICMP等不同处理流程。
 

…… 
hash = protocol & (MAX_INET_PROTOS - 1); //根据报文协议类型取hash值 
raw_sk = sk_head(&raw_v4_htable[hash]); //在raw_v4_htable中查找 
…… 
if (raw_sk && !raw_v4_input(skb, skb->nh.iph, hash)) //处理原始套接字 
…… 
if ((ipprot = rcu_dereference(inet_protos[hash])) != NULL) 
{ 
//匹配inet_protos[]数组        ……         
ret = ipprot->handler(skb); //调用传输层处理函数         
…… 
} 
else
{ 
//如果在inet_protos[]数组中未匹配到,则释放报文……         
kfree_skb(skb); 
} ……

如图6所示的inet_protos[]数组,每项由net_protocol结构组成。表示一个协议(包括传输层协议和网络层附属协议)的接收处理函数集,一般包括一个正常接收函数和一个出错接收函数。图中TCP、UDP和ICMP协议的接收处理函数分别为tcp_v4_rcv()、udp_rcv()和icmp_rcv()。如果在inet_protos[]数组中未配置到相应的net_protocol结构,报文就会被丢弃掉。比如OSPF报文(协议类型为89)在inet_protos[]数组中没有相应的项,内核会将其丢弃掉,这种报文只能提供网络层原始套接字接收到用户态来处理。

图6  inet_protos[]数组结构

    网络层原始套接字的总体接收流程如下,最终会将skb挂到相应套接字上,并唤醒用户态进程读取报文数据。

网卡驱动->netif_receive_skb()->ip_rcv()->ip_rcv_finish()->ip_local_deliver()->ip_local

_deliver_finish()->raw_v4_input()->raw_rcv()->raw_rcv_skb()->sock_queue_rcv_skb()

…… skb_queue_tail(&sk->sk_receive_queue, skb); //挂到接收队列 if (!sock_flag(sk, SOCK_DEAD))        

        sk->sk_data_ready(sk, skb_len); //唤醒用户态进程 ……

       上面介绍了报文接收在软中断的处理流程,下面介绍用户态进程读取报文是如何实现的。用户态的recvmsg()最终会调用raw_recvmsg(),后者再调用skb_recv_datagram。如果套接字接收队列sk->sk_receive_queue中有报文就取skb并返回。否则调用wait_for_packet()等待,直到内核软中断收到报文并唤醒用户态进程。

sys_recvmsg()->sock_recvmsg()->…->sock_common_recvmsg()->raw_recvmsg()

2.3.3  报文发送

用户态调用sendto()或sendmsg()发送报文的内核态处理流程如下,最终由raw_sendmsg()进行发送。

sys_sendto()->sock_sendmsg()->__sock_sendmsg()->inet_sendmsg()->raw_sendmsg()

    此函数先进行一些参数合法性检测,然后调用ip_route_output_slow()进行选路。选路成功后主要执行如下代码片段,根据inet->hdrincl是否设置走不同的流程。raw_send_hdrinc()函数表示用户态发送的数据中需要包含IP首部,即由调用者在发送时自行构造IP首部。如果inet->hdrincl未置位,表示内核会构造IP首部,即调用者发送的数据中不包含IP首部。不管走哪个流程,最终都会经过ip_output()->ip_finish_output()->…->dev_queue_xmit()将报文交给网卡驱动的发送函数发送出去。

…… if (inet->hdrincl)
{//调用者要构造IP首部         err = raw_send_hdrinc(sk, msg->msg_iov, len, rt, msg->msg_flags);
}
else 
{        …… //由内核构造IP首部        err = ip_push_pending_frames(sk); 
} ……

   注:inet->hdrincl置位表示用户态发送的数据中要包含IP首部,inet->hdrincl在以下两种情况下被置位。

    a). 给套接字设置IP_HDRINCL选项

          setsockopt (sockfd, IPPROTO_IP, IP_HDRINCL, &val, sizeof(val))

    b). 调用socket()创建套接字时,第三个参数指定为IPPROTO_RAW,见2.3.1节。

          socktet(PF_INET, SOCK_RAW, IPPROTO_RAW)

2.3.4  其它

a)       套接字绑定

若原始套接字调用bind()绑定了一个地址,则该套接口只能收到目的IP地址与绑定地址相匹配的报文。内核的具体实现是raw_bind(),将inet->rcv_saddr设置为绑定地址。在原始套接字接收时,__raw_v4_lookup()在设置了inet->rcv_saddr字段的情况下,会判断该字段是否与报文目的IP地址相同。

sys_bind()->inet_bind()->raw_bind()

b)      信息查看

网络层原始套接字的信息可通过/proc/net/raw进行查看。如下为图5所创建的3个网络层原始套接字的信息,可以查看到创建套接字时指定的协议类型、绑定的地址、发送和接收队列已使用的缓存大小等信息。这些信息对于分析和定位问题有帮助。

cat /proc/net/rawsl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode1: 00000000:0001 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 1323 2 ffff8100070b23806: 00000000:0006 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 1322 2 ffff8100070b208089: 00000000:0059 00000000:0000 07 00000000:00000000 00:00000000 00000000 0 0 1324 2 ffff8100070b2680

 三、应用及注意事项

3.1  使用链路层原始套接字

注意事项:

a)       尽量避免创建过多原始套接字,且原始套接字要尽量绑定网卡。因为收到每个报文除了会将其分发给绑定在该网卡上的原始套接字外,还会分发给没有绑定网卡的原始套接字。如果原始套接字较多,一个报文就会在软中断上下文中分发多次,造成处理时间过长。

b)      发包和收包尽量使用同一个原始套接字。如果发包与收包使用两个不同的原始套接字,会由于接收报文时分发多次而影响性能。而且用于发送的那个套接字的接收队列上也会缓存报文,直至达到接收队列大小限制,会造成内存泄露。

c)       若只接收指定类型二层报文,在调用socket()时指定第三个参数的协议类型,而最好不要使用ETH_P_ALL。因为ETH_P_ALL会接收所有类型的报文,而且还会将外发报文收回来,这样就需要做BPF过滤,比较影响性能。

3.2  使用网络层原始套接字

注意事项:

a)       由于IP报文的重组是在网络层原始套接字接收流程之前执行的,所以该原始套接字不能接收到UDP和TCP的分组数据。

b)      若原始套接字已由bind()绑定了某个本地IP地址,那么只有目的IP地址与绑定地址匹配的报文,才能递送到这个套接口上。

c)       若原始套接字已由connect()指定了某个远地IP地址,那么只有源IP地址与这个已连接地址匹配的报文,才能递送到这个套接口上。

3.3  网络诊断工具使用原始套接字

很多网络诊断工具也是利用原始套接字来实现的,经常会使用到的有tcpdump, ping和traceroute等。

tcpdump

该工具用于截获网口上的报文流量。其实现原理是创建ETH_P_ALL类型的链路层原始套接字,读取和解析报文数据并将信息显示出来。

ping

该工具用于检查网络连接。其实现原理是创建网络层原始套接字,指定协议类型为IPPROTO_ICMP。检测方构造ICMP回射请求报文(类型为ICMP_ECHO),根据ICMP协议实现,被检测方收到该请求报文后会响应一个ICMP回射应答报文(类型为ICMP_ECHOREPLY)。然后检测方通过原始套接字读取并解析应答报文,并显示出序号、TTL等信息。

traceroute

该工具用于跟踪IP报文在网络中的路由过程。其实现原理也是创建网络层原始套接字,指定协议类型为IPPROTO_ICMP。假设从A主机路由到D主机,需要依次经过B主机和C主机。使用traceroute来跟踪A主机到D主机的路由途径,具体步骤如下,在每次探测过程中会显示各节点的IP、时间等信息。

a)       A主机使用普通的UDP套接字向目的主机发送TTL为1(使用套接口选项IP_TTL来修改)的UDP报文;

b)      B主机收到该UDP报文后,由于TTL为1会拒绝转发,并且向A主机发送code为ICMP_EXC_TTL的ICMP报文;

c)       A主机用创建的网络层原始套接字读取并解析ICMP报文。如果ICMP报文code是ICMP_EXC_TTL,就将UDP报文的TTL增加1并回到步骤a)继续进行探测;如果ICMP报文的code是ICMP_PROT_UNREACH,表示UDP报文到达了目的地。

 

              A主机―>B主机―>C主机―>D主机

 

 

 


http://chatgpt.dhexx.cn/article/GYiXh3NK.shtml

相关文章

socket套接字

欢迎关注博主 Mindtechnist 或加入【Linux C/C/Python社区】一起探讨和分享Linux C/C/Python/Shell编程、机器人技术、机器学习、机器视觉、嵌入式AI相关领域的知识和技术。 socket套接字 1. 什么是socket套接字2. socket编程3. 网络字节序4. IP地址转换函数5. sockaddr数据结构…

java 套接字是什么_套接字是什么,套接字通信及其原理

为通信的端点,每个套接字由一个 IP 地址和一个端口号组成。通过网络通信的每对进程需要使用一对套接字,即每个进程各有一个。 通常,套接字采用客户机-服务器架构。服务器通过监听指定端口,来等待客户请求。服务器在收到请求后,接受来自客户套接字的连接,从而完成连接。 实…

网络编程——原始套接字实现原理

目录 1. 基础知识 1.1、概述 1.2、链路层原始套接字 1.3、网络层原始套接字 2、原始套接字的实现 2.1 原始套接字报文收发流程 2.2链路层原始套接字的实现 2.2.1 套接字创建 2.2.2 报文接收 2.2.3 报文发送 2.2.4 其它 2.3 网络层原始套接字的实现 2.3.1 套接字…

UDP套接字编程

参考:《UNIX 网络编程 卷1 : 套接字联网API》 UDP 与 TCP 之间传输存在差异,也导致编写应用程序存在很多差异。UDP 客户端和服务器不建立连接,而是直接使用 sendto 函数给服务器发送数据报。但必须指定目的地的地址作为参数。服务器也不用接…

网络套接字编程

网络套接字编程 一、 认识UDP协议 UDP(User Datagram Protocol 用户数据报协议,是不可靠的数据报传输协议,不确保数据安全有序的到达对端。 特点: 传输层协议无连接不可靠传输面向数据报 应用场景:性能要求大于安全要求&…

彻底弄懂套接字

1.什么是套接字(英文名:插座) 套接字(socket)是一种通信机制,凭借这种机制,客户/服务器系统的开发工作既可以在本地单机上进行,也可以跨网络进行。Linux所提供的功能(如打…

什么是套接字?Socket基本介绍

什么是套接字?Socket基本介绍 一、什么是套接字?二、套接字特性三、套接字缓冲区 一、什么是套接字? 套接字是一种通信机制(通信的两方的一种约定),socket屏蔽了各个协议的通信细节,提供了tcp/…

微信小程序-引入地图、获得经纬度

实际这是一个获得经纬度的方法,但是有了经纬度可以做很多事情 点击按钮跳转到一个单独的页面(地图,可导航)在页面内嵌一个独立的小区域 首先可看一下腾讯地图官方文档 微信小程序JavaScript SDK | 腾讯位置服务 最基本&#xf…

微信小程序-批量地图标记

效果图 wxml <loading hidden"{{!loading}}">加载中</loading><view class"mapBox"><map id"myMap" scale"12" longitude"{{longitude}}" latitude"{{latitude}}" markers"{{mark…

实现地图功能 利用微信内置的微信地图

效果图&#xff1a; 查看微信开发文档&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/api/location/wx.chooseLocation.html 其实不难&#xff0c;查看官方文档&#xff0c;一目了然 直接上代码&#xff1a; map.wxml: <button bindtap"mapViewTap&…

微信小程序应用百度地图API

微信小程序&#xff0c;定位地点&#xff0c;应用bdmap API 1 申请 百度地图开放平台页面&#xff1a;控制台&#xff0c;添加应用 应用类型选微信小程序&#xff0c;添加微信小程序名称和APP ID 2. 微信小程序后台设置 进入微信公众平台&#xff0c;开发管理 服务器域名&a…

微信接入js-sdk-获取地理位置,打开微信内置地图

1.第一步当然是已经正确接入了微信并且配置好了回调安全域名。不会的朋友可以看看《微信开发-初级接入微信公众平台MP》 2. 引用微信js-sdk, http://res.wx.qq.com/open/js/jweixin-1.0.0.js&#xff0c;然后通过config接口注入权限验证配置。先在自己的服务器上写个获取数据…

微信地图 leaflet 腾讯地图

本来在微信项目中使用的高德地图&#xff0c;发现不是想象中的好用&#xff0c;而且用了微信&#xff0c;感觉使用腾讯地图会比较方便&#xff0c;所以&#xff0c;索性使用leaflet腾讯地图的底图来实现。 其中关于正确使用腾讯地图参考了https://github.com/wuxiashuangji/TX…

微信地图组件小程序报错“permission“

报错原因 地图可以任意添加&#xff0c;但用户的位置属于个人隐私&#xff0c;因此需要添加服务引导程序&#xff0c;告知用户地理位置的获取。需要添加 Permission &#xff08;小程序权限获取设置&#xff09;。 解决方法 该片段用于获取位置权限&#xff0c;注意该片段如…

uniapp 微信对接地图的三种操作

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 1.uni.getLocation 获取当前经维度 先上代码 let that this// 获取用户是否开启 授权获取当前的地理位置、速度的权限。uni.getSetting({success (res) {console.log(res)// 如果没有授权if (!res.au…

微信地图多边形算法及判断点位是否在多边形中

最新一个小项目,需要用到地图定义自由区域,并判断选点是否落在此区域内,思路是通过map的polygons中的points来定义多边形边界,通过polygons的fillColor 、 strokeColor、strokeWidth来进行选区颜色的渲染。 然后再通过地图中心点位的移动来确定需要判断的选点(因为小程序地…

【微信小程序】打开微信内置的地图

前言 略 打开微信内置的地图 wx.openLocation({latitude: 38.043622, /*纬度&#xff0c;使用 gcj02 国测局坐标系*/longitude: 114.514746, /*经度&#xff0c;使用 gcj02 国测局坐标系*/scale: 18, /*缩放比例&#xff0c;范围5~18*/name: 石家庄市长安公园人民广场, /*这…

小程序 – 调用微信地图功能小记 + 滑动事件

学习文献官方API对 location 地图 API的具体分析日历插件 - github 2-有回调事件小程序滚动问题小程序上下滑动事件小程序map地图上显示多个marker wx.getLocation(Object object) -获取当前的地理位置、速度。并且能打印出地址消息&#xff1b; wx.openLocation() – 是使用…

微信地图wgs84坐标,gcj02坐标,bd09坐标转换

微信小程序三种常见经纬度坐标系的转化 遇见问题&#xff1a;在其它端点位显示正常&#xff0c;在小程序上点位发生偏移&#xff0c;微信小程序是gcj02坐标&#xff0c;就是xxToGcj02&#xff0c;具体情况具体分析 我们常用的地图api坐标系有wgs84坐标系&#xff0c;gcj02坐标…

Android仿微信地图定位和位置选择(上)

一、地图集成 集成腾讯地图SDK&#xff0c;https://lbs.qq.com/&#xff0c;申请AppKey。 1、dependencies implementation com.tencent.map.geolocation:TencentLocationSdk-openplatform:7.2.6 implementation com.tencent.map:tencent-map-vector-sdk:4.3.4 2、AndroidMa…