在Elixir中实现UDP与TCP共用53端口及Socket库推荐
解决Elixir DNS服务器绑定53端口的问题及Socket库推荐
一、绑定53端口报错的常见原因及解决办法
1. 特权端口限制
53属于系统特权端口(1-1024),非root用户无法直接绑定。解决方式有两种:
- 给Erlang虚拟机添加权限:Linux系统下执行
setcap 'cap_net_bind_service=+ep' /path/to/your/elixir_installation/bin/beam.smp,无需root即可绑定特权端口。 - 端口转发:将服务绑定到1024以上端口(如5300),再用iptables转发53端口流量:
# UDP转发 iptables -t nat -A PREROUTING -p udp --dport 53 -j REDIRECT --to-ports 5300 # TCP转发 iptables -t nat -A PREROUTING -p tcp --dport 53 -j REDIRECT --to-ports 5300
2. 端口被占用
系统默认DNS服务(如systemd-resolved、dnsmasq)通常会占用53端口,需先停止这些服务:
- 停止systemd-resolved:
sudo systemctl stop systemd-resolved && sudo systemctl disable systemd-resolved - 停止dnsmasq:
sudo systemctl stop dnsmasq && sudo systemctl disable dnsmasq
可用ss -tulpn | grep :53命令检查端口占用情况。
3. Socket参数配置问题
确保调用gen_udp:open/2和gen_tcp:listen/2时参数正确:
- UDP示例:
{:ok, udp_socket} = :gen_udp.open(53, [:binary, {:active, false}, {:reuseaddr, true}]) - TCP示例:
{:ok, tcp_socket} = :gen_tcp.listen(53, [:binary, {:active, false}, {:reuseaddr, true}, {:backlog, 100}]) # 启动进程处理TCP连接 spawn(fn -> accept_loop(tcp_socket) end) defp accept_loop(socket) do {:ok, client} = :gen_tcp.accept(socket) spawn(fn -> handle_tcp_client(client) end) accept_loop(socket) end defp handle_tcp_client(client) do case :gen_tcp.recv(client, 0) do {:ok, data} -> # 处理DNS请求逻辑 :gen_tcp.send(client, response_data) :gen_tcp.close(client) {:error, _reason} -> :gen_tcp.close(client) end end
TCP需要循环接受连接,每个连接用单独进程处理,避免阻塞。
二、好用的Elixir TCP/UDP Socket库推荐
- :ranch:Erlang官方维护的高性能Socket处理库,Elixir可直接调用。支持TCP/UDP连接池、连接管理,适合高并发场景,是很多Elixir网络服务的底层选择。
- socket:Elixir封装的Socket库,对
gen_tcp/gen_udp做了更友好的API封装,支持UDP多播、TCP TLS等功能,代码更易读。 - nimble_tcp:Dashbit出品的轻量级TCP监听库,代码简洁,适合快速搭建简单TCP服务,无多余依赖,性能出色。
内容的提问来源于stack exchange,提问作者Jonathan Kloepfer
相关产品推荐
相关产品推荐

