UDP没有连接的概念,所以UDP不会保存 “正在和谁通信的信息” ,换句话说,UDP数据的发送是oneshot的。

我们来做个实验,两台机器分别部署UDP的server和client。

先看server:

#define PORT  2222
int main()
{int sockfd;char buffer[MAXLINE];char *tosend = "aaaaaaaaaaa";struct sockaddr_in servaddr, cliaddr;sockfd = socket(AF_INET, SOCK_DGRAM, 0);servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = inet_addr("192.168.56.101");servaddr.sin_port = htons(PORT);bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr));n = recvfrom(sockfd, (char *)buffer, 64, MSG_WAITALL, ( struct sockaddr *) &cliaddr, &len);sendto(sockfd, (const char *)tosend, strlen(tosend), MSG_CONFIRM, (const struct sockaddr *) &cliaddr, len);return 0;
}

server逻辑很简单,接受client的一个buffer,然后回复一堆aaaaaaa…

再看client:

#define PORT  2222int main()
{int sockfd;char buffer[MAXLINE];char *tosend = "bbbbbbbbbbbbb";struct sockaddr_in    servaddr;sockfd = socket(AF_INET, SOCK_DGRAM, 0);servaddr.sin_family = AF_INET;servaddr.sin_port = htons(PORT);servaddr.sin_addr.s_addr = inet_addr("192.168.56.101");sendto(sockfd, (const char *)tosend, strlen(tosend), MSG_CONFIRM, (const struct sockaddr *) &servaddr, sizeof(servaddr));n = recvfrom(sockfd, (char *)buffer, 64, MSG_WAITALL, (struct sockaddr *) &servaddr, &len);printf("data: %s      %d\n", buffer, htons(servaddr.sin_port));return 0;
}

在client上配置iptables规则:

iptables -t raw -A INPUT -p udp -j NOTRAC
iptables -t nat -A INPUT -p udp --sport 2222 -j SNAT --to-source :12345

意思很简单,client给server的2222端口发送一堆b,然后server使用12345端口回复一堆a给client。作为iptables的替代,在recvfrom和sendto之间再次bind不同的address即可。

这肯定是可行的,数据是可以发送成功的。

  • 两个UDP socket互相通信,源端口是可以不断变化的。

UDP接收端在真的收到数据报文之前,是不知道源端口变化了的,按照UDP的规范,UDP socket在协议栈里不能以4元组来组织,而只能通过 {本地IP地址,本地端口} 来组织。

即便是connected UDP也不行。

connected UDP在查找时只是在compare时附加了源IP地址和源端口的检测。

这意味着一些高负载流式的UDP服务(用UDP传输流式数据,比如quic)在 连接数 (即唯一四元组的数量)很多时,socket无法通过四元组很好地进行散列,而只能退化成一条链表:

  • 服务端的端口与IP均相同。(相关的socket会hash到同一个bucket)
  • 客户端的端口与IP无法被利用(按照UDP语义和规范,它们‘可能’会发生变化)。

但是,可以为四元组加个缓存!

我们看Linux内核的实现,为了优化查询性能,在 目标端口 hash之外,引入了一个 {目标IP,目标端口} 二元组hash,当端口hash表冲突链长度大于10时,启用二元组hash查询。

然而,无济于事!

为了解决这个问题,加个四元组hash表查询缓存是一个正确的思路。缓存是规范外的。

我们可以看到,类似nf_conntrack,UDP防火墙等等均采用了 “UDP四元组作为连接性” 来优化查询性能的。我们看一个nf_conntrack的例子:

ipv4     2 udp      17 22 src=192.168.56.101 dst=192.168.56.110 sport=2222 dport=45069 [UNREPLIED] src=192.168.56.110 dst=192.168.56.101 sport=45069 dport=12345 mark=0 zone=0 use=2

实现这个代码非常简单,照猫画虎UDP socket组织的hash2即可,在hash2操作的地方,按照引入一个四元组hash3的对应操作即可:

  • udp_lib_get_port: 按照四元组插入hash3。
  • __udp4_lib_lookup_skb: 先按照四元组查询hash3。
  • udp_lib_rehash: 如果探测到元组变化,则更新hash3。
  • udp_lib_unhash: 结束时,从hash3中摘除当前socket四元组item。

是不是很简单呢?当然,经理并不这么认为。


浙江温州皮鞋湿,下雨进水不会胖。

UDP socket查询高速缓存相关推荐

  1. 【转】Linux编程之UDP SOCKET全攻略

    转自:http://www.cnblogs.com/skyfsm/p/6287787.html?utm_source=itdadao&utm_medium=referral 这篇文章将对lin ...

  2. 超详细的Linux编程之UDP SOCKET全攻略(一文让你彻底了解)

    一.基本的udp socket编程 1. UDP编程框架 要使用UDP协议进行程序开发,我们必须首先得理解什么是什么是UDP?这里简单概括一下. UDP(user datagram protocol) ...

  3. Linux Kernel TCP/IP Stack — Socket Layer — TCP/UDP Socket 网络编程

    目录 文章目录 目录 TCP/UDP Socket 逻辑架构 创建 Socket 绑定 Socket 请求建立 Socket 连接 监听 Socket 接受请求 关闭连接 数据的发送和接收 send ...

  4. LINUX下UDP实现消息镜像通信,linux环境下基于udp socket简单聊天通信

    客户端代码:client.c /* * File: main.c * Author: guanyy * * Created on 20161202 * * 主要实现:客户端和服务端相互通信 */ #i ...

  5. 内核中的UDP socket流程(2)——API “sys_socket”

    内核中的UDP socket流程(2)--API "sys_socket" 作者:gfree.wind@gmail.com 原文:http://blog.chinaunix.net ...

  6. TCP/UDP,SOCKET,HTTP,FTP协议简析

    (一)TCP/UDP,SOCKET,HTTP,FTP简析 TCP/IP是个协议组,可分为三个层次:网络层.传输层和应用层: 网络层:IP协议.ICMP协议.ARP协议.RARP协议和BOOTP协议 传 ...

  7. UDP socket programming in php

    2019独角兽企业重金招聘Python工程师标准>>> http://www.binarytides.com/udp-socket-programming-in-php/ UDP s ...

  8. UDP socket 设置为的非阻塞模式

    UDP socket 设置为的非阻塞模式  Len = recvfrom(SocketFD, szRecvBuf, sizeof(szRecvBuf), MSG_DONTWAIT, (struct s ...

  9. linux系统udp通信程序,Linux UDP socket编程(UDP通讯模型) | C/C++程序员之家

    Linux UDP socket编程(UDP通讯模型): UDPClient + UDPService. Linux下大多数网络程序都是基于TCP的,很少基于UDP,简单的通讯模型如下,开发时候备用! ...

  10. 内核中的UDP socket流程(1)

    内核中的UDP socket流程(1)  相对于TCP,UDP协议要简单的多.所以我决定由简入繁,先从UDP协议入手. 前一遍文章已经确定了struct sk_buff被用于socket的接受和发送缓 ...

最新文章

  1. UNIX文件的实现——索引节点
  2. 数据去中心化的场景与流程
  3. 王道计算机考研 数据结构 (图-上)
  4. 注释和简单用户交互程序
  5. Oracle中一般游标与REF游标的区别
  6. Linux下后台执行java程序
  7. 我敲的不是代码,而是……
  8. [网络通信协议]websocket
  9. 动易cms .net版本后台拿shell
  10. 某程序员求助:简历造假,如今面试通过,要坦白吗?
  11. 黑客攻防专题九:菜鸟 Sa 注入=肉鸡
  12. java.lang.IllegalArgumentException: Scrapped or attached views may not be recycled.
  13. Catagory添加属性、扩展方法
  14. SSD接口SATA/PCIE/mSATA/M.2分析
  15. Windows cmd 查看文件MD5 SHA1 SHA256
  16. windows 7下进入System帐号并运行桌面系统
  17. PWM调光线性恒流LED恒流芯片X10S
  18. 长尾效应解析以及长尾效应在电商中的应用
  19. windows开启远程桌面,防火墙拦截:只允许特定IP远程
  20. 一次正交设计和组合设计之旅

热门文章

  1. python写一个定时关机软件
  2. Win10打开nvidia控制面板闪退怎么解决
  3. 用计算机弹出记事本,电脑新装的系统开机后总是自动弹出记事本如何解决
  4. 使用AIDL挂断电话
  5. ubuntu环境下安装opencv教程及测试
  6. 图书馆占座系统(六)
  7. Android开机启动广播
  8. 如何无信用卡申请谷歌云
  9. 【支持4G插卡上网】京东云1代完美固件
  10. linux常用命令大全,入门基础版