Socket的UDP协议在erlang中的实现
现在我们看看UDP协议(User Datagram Protocol,用户数据报协议)。使用UDP,互联网上的机器之间可以互相发送小段的数据,叫做数据报。UDP数据报是不可靠的,这意味着如果客户端发送一系列的UDP数据报到服务器,收到的数据报顺序可能是错误的。不过收到的数据报肯定是正确的。大的数据报会被分为多个小的分片,IP协议负责重新组装这些分片,并最终交付给应用。
UDP是无连接的协议,这意味着客户端无需连接服务器即可发送消息。这也意味着程序更加适于大量客户端收发小的消息报文。
在Erlang中编写UDP客户端和服务器比TCP时更简单,因为我们无需管理连接。
1 简单的UDP服务器和客户端
首先,我们看看服务器,一个通用的服务器样式如下:
server(Port) ->
{ok,Socket} = gen_udp:open(Port,[binary]),
loop(Socket). loop(Socket) ->
receive
{udp,Socket,Host,Port,Bin} ->
BinReply = ... ,
gen_udp:send(Socket,Host,Port,BinReply),
loop(Socket)
end.
这里比TCP协议的例子更简单,因为我们至少不需要关心连接关闭的消息。注意我们以二进制方式打开socket,驱动也会以二进制数据的形式将报文发送到应用。
注意客户端。这里有个简单的客户端。它仅仅打开UDP socket,发送消息到服务器,等待响应(或超时),然后关闭socket并返回从服务器接收到的值。
client(Request) ->
{ok,Socket} = gen_udp:open(0,[binary]),
ok = gen_udp:send(Socket,"localhost",4000,Request),
Value = receive
{udp,Socket,_,_,Bin} ->
{ok,Bin}
after 2000 ->
error
end,
gen_udp:close(Socket),
Value
我们必须拥有一个超时,否则UDP的不可靠会让我们永远得不到响应。
2 一个UDP阶乘服务器
我们可以很容易的构造一个UDP的阶乘服务器。代码模仿前一节。
-module(upd_test).
-export([start_server/0,client/1]). start_server() ->
spawn(fun() -> server(4000) end).
%% 服务器
server(Port) ->
{ok,Socket}=gen_udp:open(Port,,[binary]),
io:format("server opened socket:~p~n",[Socket]),
loop(Socket). loop(Socket) ->
receive
{udp,Socket,Host,Port,Bin} =Msg ->
io:format("server received:~p~n",[Msg]),
N=binary_to_term(Bin),
Fac=fac(N),
gen_udp:send(Socket,Host,Port,term_to_binary(Fac)),
loop(Socket)
end. fac(0) -> 1;
fac(N) -> N*fac(N-1).
%% 客户端
client(N) ->
{ok,Socket} = gen_upd:open(0,[binary]),
io:format("client opened socket=~p~n",[Socket]),
ok=gen_udp:send(Socket,"localhost",4000,term_to_binary(N)),
Value=receive
{udp,Socket,_,_,Bin}=Msg ->
io:format("client received:~p~n",[Msg]),
binary_to_term(Bin)
after 2000 ->
0
end,
gen_udp:close(Socket),
Value
注意我增加了一些打印语句,所以我们可以看到程序执行的过程。我一般是开发阶段加很多打印语句,而在工作正常后就注释掉了。
现在让我们运行例子,首先启动服务器:
1> udp_test:start_server().
server opened socket:#Port<0.106>
<0.34.0>
这会在后台运行,所以我们发出一个客户端请求:
2> udp_test:client(40).
client opened socket=#Port<0.105>
server received:{udp,#Port<0.106>,{127,0,0,1},32785,<<131,97,40>>}
client received:{udp,#Port<0.105>,
{127,0,0,1},4000,
<<131,110,20,0,0,0,0,0,64,37,5,255,
100,222,15,8,126,242,199,132,27,
232,234,142>>}
815915283247897734345611269596115894272000000000
3 UDP的附加注释
我们必须注意的是UDP是无连接的协议,也就四海服务器无法拒绝客户端发送数据,甚至不知道客户端是谁。
大个的UDP报文会被切分成多个分片分别在网络上传输。分片发生在数据报长度大于最大传输单元(MTU)时,以确保通过路由器等网络设备以后仍然可以到达。一般的测量方法是开始于一个足够小的包(比如500字节),然后逐渐增加,直到发现MTU为止。如果在某一点发现数据报被丢弃了,那么,你就直到可以传输的最大报文长度了。
一个UDP数据报可以被传输两次,所以你必须小心的编码以防备这个事。因为他可能会对同一个请求的第二次出现而再做一次响应。想要防止,我们可以修改客户端代码来在每个请求中加一个唯一引用,并且检查响应中的这个唯一引用。想要生成一个唯一引用,我们可以用Erlang BIF的 make_ref ,就会生成一个全局唯一引用。远程过程调用现在可以这样写:
client(Request) ->
{ok,Socket} = gen_udp:open(0,[binary]),
Ref=make_ref(),
B1=term_to_binary({Ref,Request}),
ok=gen_udp:send(Socket,"localhost",4000,B1),
wait_for_ref(Socket,Ref). wait_for_ref(Socket,Ref) ->
receive
{udp,Socket,_,_,Bin} ->
case binary_to_term(Bin) of
{Ref,Val} ->
Val;
{_SomeOtherRef,_} ->
wait_for_ref(Socket,Ref)
end;
after 1000 ->
...
end.
ps:这里它相当于加上了个ref的唯一值,去检查clinet返回响应的做校验.
Socket的UDP协议在erlang中的实现的更多相关文章
- socket之UDP协议,并发编程介绍,操作系统发展史
socket之UDP协议 1.UDP协议 UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection 参考 ...
- C#的Socket实现UDP协议通信
今天稍花化了一点时间,利用C#的Socket验证了UDP的通信,为接下来特地利用UDP做个分布式的通信仿真系统打下基础.众所周知,UDP 就是用户数据报协议,在互联网参考模型的第四层——传输层.与TC ...
- 网络Socket编程UDP协议例子
服务端代码 public class UDPChatServer { //通讯端口 private Integer port=8000; //数据报文的通讯通道对象 private DatagramC ...
- Java的socket服务UDP协议
练习1 接收类 package com.socket.demo; import java.io.IOException; import java.net.DatagramPacket; import ...
- 通过socket和Udp协议简单实现一个群体聊天工具(控制台)
编写一个聊天程序.有收数据的部分 和 发数据的部分.这两个部分需要同时执行,这就用到多线程技术,一个线程负责收,一个现象负责发. 因为收和发动作是不一致的,所以要定义两个run方法而且这两个方法要封装 ...
- Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型
Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...
- socket、tcp/ip协议、udp协议
socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. socket起源于Un ...
- Python进阶----UDP协议使用socket通信,socketserver模块实现并发
Python进阶----UDP协议使用socket通信,socketserver模块实现并发 一丶基于UDP协议的socket 实现UDP协议传输数据 代码如下:
- 局域网内通过UDP协议进行传输接受数据——AsyncUdpSocket
在相同的局域网内,可以通过Udp协议进行数据的传输和接收,Udp协议与Http协议不同,Udp更加方便快捷,省去了很多步骤,但是也有很多传输问题,在局域网内小范围传输数据时Udp还是非常能够胜任的. ...
随机推荐
- 全面解析Vue.nextTick实现原理
vue中有一个较为特殊的API,nextTick.根据官方文档的解释,它可以在DOM更新完毕之后执行一个回调,用法如下: // 修改数据 vm.msg = 'Hello' // DOM 还没有更新 V ...
- depletion mosfet 的 depletion 解釋
Origin mosfet 除了有 n channel 及 p channel 外, 還分為 enhanced 及 depletion 兩種, 引起我注意的是, depletion 代表什麼, Exp ...
- hdu 4857(好题,反向拓扑排序)
逃生 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...
- nodejs编写实例基础操作
学习视频地址 https://cnodejs.org/topic/5a72c66ace45d440451465c3 初始化项目 首先查看项目中是否有package.json 文件,如果有可执行np ...
- AC日记——[Sdoi2010]星际竞速 bzoj 1927
1927 思路: 连边,拆点: 每个点拆成i,i+n,都向t连边: i到t表示高速模式,i+n到t表示跳跃模式: 然后读入路径,如果u>v,则交换u,v: u向v+n连边: spfa跑最小费用: ...
- 洛谷 P1865 A % B Problem[筛素数/前缀和思想/区间质数个数]
题目描述 区间质数个数 输入输出格式 输入格式: 一行两个整数 询问次数n,范围m 接下来n行,每行两个整数 l,r 表示区间 输出格式: 对于每次询问输出个数 t,如l或r∉[1,m]输出 Cros ...
- LINUX CP命令直接覆盖不提示按Y/N的方法
refer to: https://blog.csdn.net/qq_36741436/article/details/78732201 cp覆盖时,无论加什么参数-f之类的还是提示是否覆盖,当文件比 ...
- NIO2.0之copy、delete和move
转自:http://www.importnew.com/15884.html Java 7引入了NIO.2,NIO.2是继承自NIO框架,并增加了新的功能(例如:处理软链接和硬链接的功能).这篇帖子包 ...
- Jenkins+ProGet+Windows Batch搭建全自动的内部包(NuGet)打包和推送及管理平台
这一篇文章是继http://www.cnblogs.com/EasonJim/p/5954155.html的升级版,由于CCNET已经过时,所以我把打包过程的CCNET工具换成Jenkins去实现,批 ...
- Android JNI&NDK编程小结及建议
前言 由于网上关于JNI/NDK相关的知识点介绍的比较零散而且不具备参照性,所以写了这篇JNI/NDK笔记,便于作为随时查阅的工具类型的文章,本文主要的介绍了在平时项目中常用的命令.JNI数据类型.签 ...