Linux内核网络UDP数据包发送(三)——IP协议层分析

Linux阅码场 2021-07-31 17:18

1. 前言

Linux内核网络 UDP 协议层通过调用 ip_send_skb 将 skb 交给 IP 协议层,本文通过分析内核 IP 协议层的关键函数来分享内核数据包发送在 IP 协议层的处理,并分享了监控IP层的方法。

2. ip_send_skb

ip_send_skb 函数定义在 net/ipv4/ip_output.c 中,非常简短。它只是调用ip_local_out,如果调用失败,就更新相应的错误计数:

int ip_send_skb(struct net *net, struct sk_buff *skb)
{
int err;

err = ip_local_out(skb);
if (err) {
if (err > 0)
err = net_xmit_errno(err);
if (err)
IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
}

return err;
}

net_xmit_errno 函数将低层错误转换为 IP 和 UDP 协议层所能理解的错误。如果发生错误, IP 协议计数器 OutDiscards 会递增。稍后我们将看到读取哪些文件可以获取此统计信息。接下来看 ip_local_out

3. ip_local_out and __ip_local_out

ip_local_out 和__ip_local_out 都很简单。ip_local_out 只需调用__ip_local_out,如果返回值为 1,则调用路由层 dst_output 发送数据包:

int ip_local_out(struct sk_buff *skb)
{
int err;

err = __ip_local_out(skb);
if (likely(err == 1))
err = dst_output(skb);

return err;
}

接下来看__ip_local_out 的代码:

int __ip_local_out(struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);

iph->tot_len = htons(skb->len);
ip_send_check(iph);
return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL,
skb_dst(skb)->dev, dst_output);
}

可以看到,该函数首先做了两件重要的事情:

  1. 设置 IP 数据包的长度

  2. 调用 ip_send_check 来计算要写入 IP 头的校验和。ip_send_check 函数将进一步调用名为 ip_fast_csum 的函数来计算校验和。在 x86 和 x86_64 体系结构上,此函数用汇编实 现。

接下来,IP 协议层将通过调用 nf_hook 进入 netfilter,其返回值将传递回 ip_local_out 。如果 nf_hook 返回 1,则表示允许数据包通过,并且调用者应该自己发送数据包。这正是我们在上面看到的情况:ip_local_out 检查返回值 1 时,自己通过调用 dst_output 发送数据包。

3.1 netfilter and nf_hook

nf_hook 只是一个 wrapper,它调用 nf_hook_thresh,首先检查是否有为这个协议族hook 类型(这里分别为 NFPROTO_IPV4 和 NF_INET_LOCAL_OUT)安装的过滤器,然后将返回到 IP 协议层,避免深入到 netfilter 或更下面,比如 iptables 和 conntrack。

如果有非常多或者非常复杂的 netfilter 或 iptables 规则,那些规则将在触发 sendmsg 系统调的用户进程的上下文中执行。如果对这个用户进程设置了 CPU 亲和性,相应的 CPU 将花费系统时间(system time)处理出站(outbound)iptables 规则。如果做性能回归测试,那可能要考虑根据系统的负载,将相应的用户进程绑到到特定的 CPU,或者是减少 netfilter/iptables 规则的复杂度,以减少对性能测试的影响。

出于讨论目的,我们假设 nf_hook 返回 1,表示调用者(在这种情况下是 IP 协议层)应该自己发送数据包。

3.2 目的(路由)缓存

dst 代码在 Linux 内核中实现协议无关的目标缓存。为了继续学习发送 UDP 数据报的流程 ,我们需要了解 dst 条目是如何被设置的,首先来看 dst 条目和路由是如何生成的。目标缓存,路由和邻居子系统,任何一个都可以拿来单独详细的介绍。现在不深入细节,只是快速地看一下它们是如何组合到一起的。

上面看到的代码调用了 dst_output(skb)。此函数只是查找关联到这个 skb 的 dst 条目 ,然后调用 output 方法。代码如下:

/* Output packet to network from transport.  */
static inline int dst_output(struct sk_buff *skb)
{
return skb_dst(skb)->output(skb);
}

看起来很简单,但是 output 方法之前是如何关联到 dst 条目的?

首先很重要的一点,目标缓存条目是以多种不同方式添加的。到目前为止,我们已经在代码中看到的一种方法是从 udp_sendmsg 调用ip_route_output_flowip_route_output_flow 函数调用 __ip_route_output_key ,后者进而调用 __mkroute_output。 __mkroute_output 函数创建路由和目标缓存条目。当它执行创建操作时,它会判断哪个 output 方法适合此 dst。大多数时候,这个函数是 ip_output

4. ip_output

在 UDP IPv4 情况下,上面的 output 方法指向的是 ip_output:

int ip_output(struct sk_buff *skb)
{
struct net_device *dev = skb_dst(skb)->dev;

IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len);

skb->dev = dev;
skb->protocol = htons(ETH_P_IP);

return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL, dev,
ip_finish_output,
!(IPCB(skb)->flags & IPSKB_REROUTED));
}

首先,更新 IPSTATS_MIB_OUT 统计计数。IP_UPD_PO_STATS 宏将更新字节数和包数统计。接下来,设置要发送此 skb 的设备,以及协议。

最后,通过调用 NF_HOOK_COND 将控制权交给 netfilter。查看 NF_HOOK_COND 的函数原型 有助于更清晰地解释它如何工作:

static inline int
NF_HOOK_COND(uint8_t pf, unsigned int hook, struct sk_buff *skb,
struct net_device *in, struct net_device *out,
int (*okfn)(struct sk_buff *), bool cond)

NF_HOOK_COND 通过检查传入的条件来工作。在这里条件是!(IPCB(skb)->flags & IPSKB_REROUTED。如果此条件为真,则 skb 将发送给 netfilter。如果 netfilter 允许包通过 ,okfn 回调函数将被调用。在这里,okfn 是 ip_finish_output

5. ip_finish_output

static int ip_finish_output(struct sk_buff *skb)
{
#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
/* Policy lookup after SNAT yielded a new policy */
if (skb_dst(skb)->xfrm != NULL) {
IPCB(skb)->flags |= IPSKB_REROUTED;
return dst_output(skb);
}
#endif
if (skb->len > ip_skb_dst_mtu(skb) && !skb_is_gso(skb))
return ip_fragment(skb, ip_finish_output2);
else
return ip_finish_output2(skb);
}

如果内核启用了 netfilter 和数据包转换(XFRM),则更新 skb 的标志并通过 dst_output 将 其发回。

更常见的两种情况是:

  1. 如果数据包的长度大于 MTU 并且分片不会 offload 到设备,则会调用 ip_fragment 在发送之前对数据包进行分片

  2. 否则,数据包将直接发送到 ip_finish_output2

Path MTU Discovery

Linux 提供了一个功能:路径 MTU 发现 。此功能允许内核自动确定路由的最大传输单元( MTU )。发送小于或等于该路由的 MTU 的包意味着可以避免 IP 分片,这是推荐设置,因为数据包分片会消耗系统资源,而避免分片看起来很容易:只需发送足够小的不需要分片的数据包。

可以在应用程序中通过调用 setsockopt 带 SOL_IP 和 IP_MTU_DISCOVER 选项,在 packet 级别来调整路径 MTU 发现设置,相应的合法值参考 IP 协议的man page。例如,可能想设置的值是 :IP_PMTUDISC_DO,表示“始终执行路径 MTU 发现”。更高级的网络应用程序或诊断工具可能选择自己实现RFC 4821,以在应用程序启动时针对特定的路由做 PMTU。在这种情况下,可以使用 IP_PMTUDISC_PROBE 选项告诉内核设置“Do not Fragment”位,这就会允许发送大于 PMTU 的数据。

应用程序可以通过调用 getsockopt 带 SOL_IP 和 IP_MTU 选项来查看当前 PMTU。可以使用它指导应用程序在发送之前,构造 UDP 数据报的大小。

如果已启用 PMTU 发现,则发送大于 PMTU 的 UDP 数据将导致应用程序收到 EMSGSIZE 错误。这种情况下,应用程序只能减小 packet 大小重试。

强烈建议启用 PTMU 发现,当查看 IP 协议层统计信息时,将解释所有统计信息,包括与分片相关的统计信息。其中许多计数都在 ip_fragment 中更新的。不管分片与否,代码最后都会调到 ip_finish_output2

6. ip_finish_output2

IP 分片后调用 ip_finish_output2,另外 ip_finish_output 也会直接调用它。这个函数在将包发送到邻居缓存之前处理各种统计计数器:

static inline int ip_finish_output2(struct sk_buff *skb)
{

/* variable declarations */

if (rt->rt_type == RTN_MULTICAST) {
IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len);
} else if (rt->rt_type == RTN_BROADCAST)
IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTBCAST, skb->len);

/* Be paranoid, rather than too clever. */
if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
struct sk_buff *skb2;

skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
if (skb2 == NULL) {
kfree_skb(skb);
return -ENOMEM;
}
if (skb->sk)
skb_set_owner_w(skb2, skb->sk);
consume_skb(skb);
skb = skb2;
}

如果与此数据包关联的路由是多播类型,则使用 IP_UPD_PO_STATS 宏来增加 OutMcastPkts 和 OutMcastOctets 计数。如果广播路由,则会增加 OutBcastPkts 和 OutBcastOctets 计数。

接下来,确保 skb 结构有足够的空间容纳需要添加的任何链路层头。如果空间不够,则调用 skb_realloc_headroom 分配额外的空间,并且新的 skb 的费用(charge)记在相关的 socket 上。

        rcu_read_lock_bh();
nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr);
neigh = __ipv4_neigh_lookup_noref(dev, nexthop);
if (unlikely(!neigh))
neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);

继续,查询路由层找到下一跳,再根据下一跳信息查找邻居缓存。如果未找到,则调用__neigh_create 创建一个邻居。例如,第一次将数据发送到另一台主机的时候,就是这种情况。创建邻居缓存的时候带了 arp_tbl参数。其他系统(如 IPv6 或 DECnet)维护自己的 ARP 表,并将不同的变量传给__neigh_create。邻居缓存如果创建, 会导致缓存表增大。邻居缓存会导出一组统计信息,以便可以衡量这种增长。

        if (!IS_ERR(neigh)) {
int res = dst_neigh_output(dst, neigh, skb);

rcu_read_unlock_bh();
return res;
}
rcu_read_unlock_bh();

net_dbg_ratelimited("%s: No header cache and no neighbour!\n",
__func__);
kfree_skb(skb);
return -EINVAL;
}

最后,如果创建邻居缓存成功,则调用 dst_neigh_output 继续传递 skb;否则,释放 skb 并返回 EINVAL,这会向上传递,导致 OutDiscards 在 ip_send_skb 中递增。

7. dst_neigh_output

dst_neigh_output 函数做了两件重要的事情。首先,如果用户调用 sendmsg 并通过辅助消息指定 MSG_CONFIRM 参数,则会设置一个标志位以指示目标高速缓存条目仍然有效且不应进行垃圾回收。这个检查就是在这个函数里面做的,并且邻居上的 confirm 字段设置为当前的 jiffies 计数。

static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n,
struct sk_buff *skb)
{
const struct hh_cache *hh;

if (dst->pending_confirm) {
unsigned long now = jiffies;

dst->pending_confirm = 0;
/* avoid dirtying neighbour */
if (n->confirmed != now)
n->confirmed = now;
}

其次,检查邻居的状态并调用适当的 output 函数。

        hh = &n->hh;
if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
return neigh_hh_output(hh, skb);
else
return n->output(n, skb);
}

邻居被认为是 NUD_CONNECTED,如果它满足以下一个或多个条件:

  1. NUD_PERMANENT:静态路由

  2. NUD_NOARP:不需要 ARP 请求(例如,目标是多播或广播地址,或环回设备)

  3. NUD_REACHABLE:邻居是“可达的。”只要成功处理了ARP 请求,目标就会被标记为可达

进一步,如果“硬件头”(hh)被缓存(之前已经发送过数据,并生成了缓存),将调用 neigh_hh_output

否则,调用 output 函数。

以上两种情况,最后都会到 dev_queue_xmit,它将 skb 发送给 Linux 网络设备子系统,在它 进入设备驱动程序层之前将对其进行更多处理。让我们沿着 neigh_hh_output 和 n->output 代码继续向下,直到达到 dev_queue_xmit

7.1 neigh_hh_output

如果目标是 NUD_CONNECTED 并且硬件头已被缓存,则将调用 neigh_hh_output,在将 skb 移交 给 dev_queue_xmit 之前执行一小部分处理 :

static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb)
{
unsigned int seq;
int hh_len;

do {
seq = read_seqbegin(&hh->hh_lock);
hh_len = hh->hh_len;
if (likely(hh_len <= HH_DATA_MOD)) {
/* this is inlined by gcc */
memcpy(skb->data - HH_DATA_MOD, hh->hh_data, HH_DATA_MOD);
} else {
int hh_alen = HH_DATA_ALIGN(hh_len);

memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
}
} while (read_seqretry(&hh->hh_lock, seq));

skb_push(skb, hh_len);
return dev_queue_xmit(skb);
}

这个函数理解有点难,部分原因是seqlock这个东西,它用于在缓存的硬件头上做读/写锁。可以将上面的 do {} while ()循环想象成一个简单的重试机制,它将尝试在循环中执行,直到成功。

循环里处理硬件头的长度对齐。这是必需的,因为某些硬件头(如IEEE 802.11 头)大于 HH_DATA_MOD(16 字节)。

将头数据复制到 skb 后,skb_push 将更新 skb 内指向数据缓冲区的指针。最后调用 dev_queue_xmit 将 skb 传递给 Linux 网络设备子系统。

7.2 n->output

如果目标不是 NUD_CONNECTED 或硬件头尚未缓存,则代码沿 n->output 路径向下。neigbour 结构上的 output 指针指向哪个函数?这得看情况。要了解这是如何设置的,我们需要更多地了解邻居缓存的工作原理。

struct neighbour 包含几个重要字段:我们在上面看到的 nud_state 字段,output 函数和 ops 结构。回想一下,我们之前看到如果在缓存中找不到现有条目,会从 ip_finish_output2 调用__neigh_create 创建一个。当调用__neigh_creaet 时,将分配邻居,其 output 函数最初设置为 neigh_blackhole。随着__neigh_create 代码的进行,它将根据邻居的状态修改 output 值以指向适当的发送方法。

例如,当代码确定是“已连接的”邻居时,neigh_connect 会将 output 设置为 neigh->ops->connected_output。或者,当代码怀疑邻居可能已关闭时,neigh_suspect 会将 output 设置为 neigh->ops->output(例如,如果已超过 /proc/sys/net/ipv4/neigh/default/delay_first_probe_time 自发送探测以来的 delay_first_probe_time 秒)。

换句话说:neigh->output 会被设置为 neigh->ops_connected_output 或 neigh->ops->output,具体取决于邻居的状态。neigh->ops 来自哪里?

分配邻居后,调用 arp_constructor(net/ipv4/arp.c )来设置 struct neighbor 的某些字段。特别是,此函数会检查与此邻居关联的设备是否导出来一个 struct header_ops 实例, 该结构体有一个 cache 方法。

neigh->ops 设置为 net/ipv4/arp 中定义的以下实例:

static const struct neigh_ops arp_hh_ops = {
.family = AF_INET,
.solicit = arp_solicit,
.error_report = arp_error_report,
.output = neigh_resolve_output,
.connected_output = neigh_resolve_output,
};

所以,不管 neighbor 是不是“已连接的”,或者邻居缓存代码是否怀疑连接“已关闭”, neigh_resolve_output 最终都会被赋给 neigh->output。当执行到 n->output 时就会调用它。

7.3 neigh_resolve_output

此函数的目的是解析未连接的邻居,或已连接但没有缓存硬件头的邻居。

/* Slow and careful. */

int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
int rc = 0;

if (!dst)
goto discard;

if (!neigh_event_send(neigh, skb)) {
int err;
struct net_device *dev = neigh->dev;
unsigned int seq;

代码首先进行一些基本检查,然后调用 neigh_event_send。 neigh_event_send 函数是 __neigh_event_send 的简单封装,后者干大部分脏话累活。可以在 net/core/neighbour.c 中读__neigh_event_send 的源代码,从大的层面看,三种情况:

  1. NUD_NONE 状态(默认状态)的邻居:假设 /proc/sys/net/ipv4/neigh/default/app_solicit 和 /proc/sys/net/ipv4/neigh/default/mcast_solicit 配置允许发送探测(如果不是, 则将状态标记为 NUD_FAILED),将导致立即发送 ARP 请求。邻居状态将更新为 NUD_INCOMPLETE

  2. NUD_STALE 状态的邻居:将更新为 NUD_DELAYED 并且将设置计时器以稍后探测它们( 稍后是现在的时间+/proc/sys/net/ipv4/neigh/default/delay_first_probe_time 秒 )

  3. 检查 NUD_INCOMPLETE 状态的邻居(包括上面第一种情形),以确保未解析邻居的排 队 packet 的数量小于等于/proc/sys/net/ipv4/neigh/default/unres_qlen。如果超过 ,则数据包会出列并丢弃,直到小于等于 proc 中的值。统计信息中有个计数器会因此 更新

如果需要 ARP 探测,ARP 将立即被发送。__neigh_event_send 将返回 0,表示邻居被视为“已 连接”或“已延迟”,否则返回 1。返回值 0 允许 neigh_resolve_output 继续:

                if (dev->header_ops->cache && !neigh->hh.hh_len)
neigh_hh_init(neigh, dst);

如果邻居关联的设备的协议实现(在我们的例子中是以太网)支持缓存硬件头,并且当前没有缓存,neigh_hh_init 将缓存它。

                do {
__skb_pull(skb, skb_network_offset(skb));
seq = read_seqbegin(&neigh->ha_lock);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
} while (read_seqretry(&neigh->ha_lock, seq));

接下来,seqlock 锁控制对邻居的硬件地址字段(neigh->ha)的访问。dev_hard_header 为 skb 创建以太网头时将读取该字段。之后是错误检查:

                if (err >= 0)
rc = dev_queue_xmit(skb);
else
goto out_kfree_skb;
}

如果以太网头写入成功,将调用 dev_queue_xmit 将 skb 传递给 Linux 网络设备子系统进行发 送。如果出现错误,goto 将删除 skb,设置并返回错误码:

out:
return rc;
discard:
neigh_dbg(1, "%s: dst=%p neigh=%p\n", __func__, dst, neigh);
out_kfree_skb:
rc = -EINVAL;
kfree_skb(skb);
goto out;
}
EXPORT_SYMBOL(neigh_resolve_output);

接下来看一些用于监控和转换 IP 协议层的文件。

8. 监控: IP 层

8.1 /proc/net/snmp


这个文件包扩多种协议的统计,IP 层的在最前面,每一列代表什么有说明。

前面我们已经看到 IP 协议层有一些地方会更新计数器。这些计数器的类型是 C 枚举类型,定义在include/uapi/linux/snmp.h:

enum
{
IPSTATS_MIB_NUM = 0,
/* frequently written fields in fast path, kept in same cache line */
IPSTATS_MIB_INPKTS, /* InReceives */
IPSTATS_MIB_INOCTETS, /* InOctets */
IPSTATS_MIB_INDELIVERS, /* InDelivers */
IPSTATS_MIB_OUTFORWDATAGRAMS, /* OutForwDatagrams */
IPSTATS_MIB_OUTPKTS, /* OutRequests */
IPSTATS_MIB_OUTOCTETS, /* OutOctets */

/* ... */

一些有趣的统计:

  • OutRequests: Incremented each time an IP packet is attempted to be sent. It appears that this is incremented for every send, successful or not.

  • OutDiscards: Incremented each time an IP packet is discarded. This can happen if appending data to the skb (for corked sockets) fails, or if the layers below IP return an error.

  • OutNoRoute: Incremented in several places, for example in the UDP protocol layer (udp_sendmsg) if no route can be generated for a given destination. Also incremented when an application calls “connect” on a UDP socket but no route can be found.

  • FragOKs: Incremented once per packet that is fragmented. For example, a packet split into 3 fragments will cause this counter to be incremented once.

  • FragCreates: Incremented once per fragment that is created. For example, a packet split into 3 fragments will cause this counter to be incremented thrice.

  • FragFails: Incremented if fragmentation was attempted, but is not permitted (because the “Don’t Fragment” bit is set). Also incremented if outputting the fragment fails.

8.2 /proc/net/netstat


格式与前面的类似,除了每列的名称都有 IpExt 前缀之外。

一些有趣的统计:

  • OutMcastPkts: Incremented each time a packet destined for a multicast address is sent.

  • OutBcastPkts: Incremented each time a packet destined for a broadcast address is sent.

  • OutOctects: The number of packet bytes output.

  • OutMcastOctets: The number of multicast packet bytes output.

  • OutBcastOctets: The number of broadcast packet bytes output.

9. 总结

Linux内核网络数据包发送时,主要用到 ip_send_skb、 ip_local_outip_outputip_finish_outputip_finish_output2、 dst_neigh_output等函数,本文通过分析这些函数来分享Linux内核数据包发送在 IP 层的处理,并对 IP 层进行了数据监控。

Reference:

https://blog.packagecloud.io/eng/2017/02/06/monitoring-tuning-linux-networking-stack-sending-data

Linux阅码场 专业的Linux技术社区和Linux操作系统学习平台,内容涉及Linux内核,Linux内存管理,Linux进程管理,Linux文件系统和IO,Linux性能调优,Linux设备驱动以及Linux虚拟化和云计算等各方各面.
评论
  • 随着智慧科技的快速发展,智能显示器的生态圈应用变得越来越丰富多元,智能显示器不仅仅是传统的显示设备,透过结合人工智能(AI)和语音助理,它还可以成为家庭、办公室和商业环境中的核心互动接口。提供多元且个性化的服务,如智能家居控制、影音串流拨放、实时信息显示等,极大提升了使用体验。此外,智能家居系统的整合能力也不容小觑,透过智能装置之间的无缝连接,形成了强大的多元应用生态圈。企业也利用智能显示器进行会议展示和多方远程合作,大大提高效率和互动性。Smart Display Ecosystem示意图,作
    百佳泰测试实验室 2025-01-16 15:37 116浏览
  • 近期,智能家居领域Matter标准的制定者,全球最具影响力的科技联盟之一,连接标准联盟(Connectivity Standards Alliance,简称CSA)“利好”频出,不仅为智能家居领域的设备制造商们提供了更为快速便捷的Matter认证流程,而且苹果、三星与谷歌等智能家居平台厂商都表示会接纳CSA的Matter认证体系,并计划将其整合至各自的“Works with”项目中。那么,在本轮“利好”背景下,智能家居的设备制造商们该如何捉住机会,“掘金”万亿市场呢?重认证快通道计划,为家居设备
    华普微HOPERF 2025-01-16 10:22 123浏览
  • 故障现象 一辆2007款法拉利599 GTB车,搭载6.0 L V12自然吸气发动机(图1),累计行驶里程约为6万km。该车因发动机故障灯异常点亮进厂检修。 图1 发动机的布置 故障诊断接车后试车,发动机怠速轻微抖动,发动机故障灯长亮。用故障检测仪检测,发现发动机控制单元(NCM)中存储有故障代码“P0300 多缸失火”“P0309 气缸9失火”“P0307 气缸7失火”,初步判断发动机存在失火故障。考虑到该车使用年数较长,决定先使用虹科Pico汽车示波器进行相对压缩测试,以
    虹科Pico汽车示波器 2025-01-15 17:30 74浏览
  • 百佳泰特为您整理2025年1月各大Logo的最新规格信息,本月有更新信息的logo有HDMI、Wi-Fi、Bluetooth、DisplayHDR、ClearMR、Intel EVO。HDMI®▶ 2025年1月6日,HDMI Forum, Inc. 宣布即将发布HDMI规范2.2版本。新规范将支持更高的分辨率和刷新率,并提供更多高质量选项。更快的96Gbps 带宽可满足数据密集型沉浸式和虚拟应用对传输的要求,如 AR/VR/MR、空间现实和光场显示,以及各种商业应用,如大型数字标牌、医疗成像和
    百佳泰测试实验室 2025-01-16 15:41 111浏览
  •  光伏及击穿,都可视之为 复合的逆过程,但是,复合、光伏与击穿,不单是进程的方向相反,偏置状态也不一样,复合的工况,是正偏,光伏是零偏,击穿与漂移则是反偏,光伏的能源是外来的,而击穿消耗的是结区自身和电源的能量,漂移的载流子是 客席载流子,须借外延层才能引入,客席载流子 不受反偏PN结的空乏区阻碍,能漂不能漂,只取决于反偏PN结是否处于外延层的「射程」范围,而穿通的成因,则是因耗尽层的过度扩张,致使跟 端子、外延层或其他空乏区 碰触,当耗尽层融通,耐压 (反向阻断能力) 即告彻底丧失,
    MrCU204 2025-01-17 11:30 47浏览
  • 一个易用且轻量化的UI可以大大提高用户的使用效率和满意度——通过快速启动、直观操作和及时反馈,帮助用户快速上手并高效完成任务;轻量化设计则可以减少资源占用,提升启动和运行速度,增强产品竞争力。LVGL(Light and Versatile Graphics Library)是一个免费开源的图形库,专为嵌入式系统设计。它以轻量级、高效和易于使用而著称,支持多种屏幕分辨率和硬件配置,并提供了丰富的GUI组件,能够帮助开发者轻松构建出美观且功能强大的用户界面。近期,飞凌嵌入式为基于NXP i.MX9
    飞凌嵌入式 2025-01-16 13:15 108浏览
  • 食物浪费已成为全球亟待解决的严峻挑战,并对环境和经济造成了重大影响。最新统计数据显示,全球高达三分之一的粮食在生产过程中损失或被无谓浪费,这不仅导致了资源消耗,还加剧了温室气体排放,并带来了巨大经济损失。全球领先的光学解决方案供应商艾迈斯欧司朗(SIX:AMS)近日宣布,艾迈斯欧司朗基于AS7341多光谱传感器开发的创新应用来解决食物浪费这一全球性难题。其多光谱传感解决方案为农业与食品行业带来深远变革,该技术通过精确判定最佳收获时机,提升质量控制水平,并在整个供应链中有效减少浪费。 在2024
    艾迈斯欧司朗 2025-01-14 18:45 106浏览
  • 数字隔离芯片是现代电气工程师在进行电路设计时所必须考虑的一种电子元件,主要用于保护低压控制电路中敏感电子设备的稳定运行与操作人员的人身安全。其不仅能隔离两个或多个高低压回路之间的电气联系,还能防止漏电流、共模噪声与浪涌等干扰信号的传播,有效增强电路间信号传输的抗干扰能力,同时提升电子系统的电磁兼容性与通信稳定性。容耦隔离芯片的典型应用原理图值得一提的是,在电子电路中引入隔离措施会带来传输延迟、功耗增加、成本增加与尺寸增加等问题,而数字隔离芯片的目标就是尽可能消除这些不利影响,同时满足安全法规的要
    华普微HOPERF 2025-01-15 09:48 140浏览
  • 随着消费者对汽车驾乘体验的要求不断攀升,汽车照明系统作为确保道路安全、提升驾驶体验以及实现车辆与环境交互的重要组成,日益受到业界的高度重视。近日,2024 DVN(上海)国际汽车照明研讨会圆满落幕。作为照明与传感创新的全球领导者,艾迈斯欧司朗受邀参与主题演讲,并现场展示了其多项前沿技术。本届研讨会汇聚来自全球各地400余名汽车、照明、光源及Tier 2供应商的专业人士及专家共聚一堂。在研讨会第一环节中,艾迈斯欧司朗系统解决方案工程副总裁 Joachim Reill以深厚的专业素养,主持该环节多位
    艾迈斯欧司朗 2025-01-16 20:51 41浏览
  • 晶台光耦KL817和KL3053在小家电产品(如微波炉等)辅助电源中的广泛应用。具备小功率、高性能、高度集成以及低待机功耗的特点,同时支持宽输入电压范围。▲光耦在实物应用中的产品图其一次侧集成了交流电压过零检测与信号输出功能,该功能产生的过零信号可用于精确控制继电器、可控硅等器件的过零开关动作,从而有效减小开关应力,显著提升器件的使用寿命。通过高度的集成化和先进的控制技术,该电源大幅减少了所需的外围器件数量,不仅降低了系统成本和体积,还进一步增强了整体的可靠性。▲电路示意图该电路的过零检测信号由
    晶台光耦 2025-01-16 10:12 79浏览
  • 日前,商务部等部门办公厅印发《手机、平板、智能手表(手环)购新补贴实施方案》明确,个人消费者购买手机、平板、智能手表(手环)3类数码产品(单件销售价格不超过6000元),可享受购新补贴。每人每类可补贴1件,每件补贴比例为减去生产、流通环节及移动运营商所有优惠后最终销售价格的15%,每件最高不超过500元。目前,京东已经做好了承接手机、平板等数码产品国补优惠的落地准备工作,未来随着各省市关于手机、平板等品类的国补开启,京东将第一时间率先上线,满足消费者的换新升级需求。为保障国补的真实有效发放,基于
    华尔街科技眼 2025-01-17 10:44 40浏览
  • 80,000人到访的国际大展上,艾迈斯欧司朗有哪些亮点?感未来,光无限。近日,在慕尼黑electronica 2024现场,ams OSRAM通过多款创新DEMO展示,以及数场前瞻洞察分享,全面展示自身融合传感器、发射器及集成电路技术,精准捕捉并呈现环境信息的卓越能力。同时,ams OSRAM通过展会期间与客户、用户等行业人士,以及媒体朋友的深度交流,向业界传达其以光电技术为笔、以创新为墨,书写智能未来的深度思考。electronica 2024electronica 2024构建了一个高度国际
    艾迈斯欧司朗 2025-01-16 20:45 35浏览
  • 电竞鼠标应用环境与客户需求电竞行业近年来发展迅速,「鼠标延迟」已成为决定游戏体验与比赛结果的关键因素。从技术角度来看,传统鼠标的延迟大约为20毫秒,入门级电竞鼠标通常为5毫秒,而高阶电竞鼠标的延迟可降低至仅2毫秒。这些差异看似微小,但在竞技激烈的游戏中,尤其在对反应和速度要求极高的场景中,每一毫秒的优化都可能带来致胜的优势。电竞比赛的普及促使玩家更加渴望降低鼠标延迟以提升竞技表现。他们希望通过精确的测试,了解不同操作系统与设定对延迟的具体影响,并寻求最佳配置方案来获得竞技优势。这样的需求推动市场
    百佳泰测试实验室 2025-01-16 15:45 146浏览
  • 实用性高值得收藏!! (时源芯微)时源专注于EMC整改与服务,配备完整器件 TVS全称Transient Voltage Suppre,亦称TVS管、瞬态抑制二极管等,有单向和双向之分。单向TVS 一般应用于直流供电电路,双向TVS 应用于电压交变的电路。在直流电路的应用中,TVS被并联接入电路中。在电路处于正常运行状态时,TVS会保持截止状态,从而不对电路的正常工作产生任何影响。然而,一旦电路中出现异常的过电压,并且这个电压达到TVS的击穿阈值时,TVS的状态就会
    时源芯微 2025-01-16 14:23 111浏览
  • 全球领先的光学解决方案供应商艾迈斯欧司朗(SIX:AMS)近日宣布,与汽车技术领先者法雷奥合作,采用创新的开放系统协议(OSP)技术,旨在改变汽车内饰照明方式,革新汽车行业座舱照明理念。结合艾迈斯欧司朗开创性的OSIRE® E3731i智能LED和法雷奥的动态环境照明系统,两家公司将为车辆内饰设计和功能设立一套全新标准。汽车内饰照明的作用日益凸显,座舱设计的主流趋势应满足终端用户的需求:即易于使用、个性化,并能提供符合用户生活方式的清晰信息。因此,动态环境照明带来了众多新机遇。智能LED的应用已
    艾迈斯欧司朗 2025-01-15 19:00 65浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦