热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Socket的UDP协议在erlang中的实现

现在我们看看UDP协议(UserDatagramProtocol,用户数据报协议)。使用UDP,互联网上的机器之间可以互相发送小段的数据,

现在我们看看UDP协议(User Datagram Protocol,用户数据报协议)。使用UDP,互联网上的机器之间可以互相发送小段的数据,叫做数据报。UDP数据报是不可靠的,这意味着如果客户端发送一系列的UDP数据报到服务器,收到的数据报顺序可能是错误的。不过收到的数据报肯定是正确的。大的数据报会被分为多个小的分片,IP协议负责重新组装这些分片,并最终交付给应用。

UDP是无连接的协议,这意味着客户端无需连接服务器即可发送消息。这也意味着程序更加适于大量客户端收发小的消息报文。

在Erlang中编写UDP客户端和服务器比TCP时更简单,因为我们无需管理连接。

 

1   简单的UDP服务器和客户端

首先,我们看看服务器,一个通用的服务器样式如下:

1 server(Port) ->
2 {ok,Socket} = gen_udp:open(Port,[binary]),
3 loop(Socket).
4
5 loop(Socket) ->
6 receive
7 {udp,Socket,Host,Port,Bin} ->
8 BinReply = ... ,
9 gen_udp:send(Socket,Host,Port,BinReply),
10 loop(Socket)
11 end.

View Code

 

这里比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 ->errorend,gen_udp:close(Socket),Value

View Code

 

我们必须拥有一个超时,否则UDP的不可靠会让我们永远得不到响应。

 

2   一个UDP阶乘服务器

我们可以很容易的构造一个UDP的阶乘服务器。代码模仿前一节。

-module(upd_test).
-export([start_server/0,client/1]).start_server() ->spawn(fun() -> server(4000) end).

View Code

 

%% 服务器

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).

View Code

 

%% 客户端

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 ->0end,gen_udp:close(Socket),Value

View Code

 

注意我增加了一些打印语句,所以我们可以看到程序执行的过程。我一般是开发阶段加很多打印语句,而在工作正常后就注释掉了。

现在让我们运行例子,首先启动服务器:

1> udp_test:start_server().
server opened socket:#Port<0.106>
<0.34.0>

这会在后台运行&#xff0c;所以我们发出一个客户端请求:

2> udp_test:client(40).
client opened socket&#61;#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是无连接的协议&#xff0c;也就四海服务器无法拒绝客户端发送数据&#xff0c;甚至不知道客户端是谁。

大个的UDP报文会被切分成多个分片分别在网络上传输。分片发生在数据报长度大于最大传输单元(MTU)时&#xff0c;以确保通过路由器等网络设备以后仍然可以到达。一般的测量方法是开始于一个足够小的包(比如500字节)&#xff0c;然后逐渐增加&#xff0c;直到发现MTU为止。如果在某一点发现数据报被丢弃了&#xff0c;那么&#xff0c;你就直到可以传输的最大报文长度了。

一个UDP数据报可以被传输两次&#xff0c;所以你必须小心的编码以防备这个事。因为他可能会对同一个请求的第二次出现而再做一次响应。想要防止&#xff0c;我们可以修改客户端代码来在每个请求中加一个唯一引用&#xff0c;并且检查响应中的这个唯一引用。想要生成一个唯一引用&#xff0c;我们可以用Erlang BIF的 make_ref &#xff0c;就会生成一个全局唯一引用。远程过程调用现在可以这样写:

client(Request) ->{ok,Socket} &#61; gen_udp:open(0,[binary]),Ref&#61;make_ref(),B1&#61;term_to_binary({Ref,Request}),ok&#61;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.

View Code

 

 ps&#xff1a;这里它相当于加上了个ref的唯一值&#xff0c;去检查clinet返回响应的做校验.

转:https://www.cnblogs.com/unqiang/p/4224141.html



推荐阅读
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文详细介绍了MySQL表分区的创建、增加和删除方法,包括查看分区数据量和全库数据量的方法。欢迎大家阅读并给予点评。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了使用cacti监控mssql 2005运行资源情况的操作步骤,包括安装必要的工具和驱动,测试mssql的连接,配置监控脚本等。通过php连接mssql来获取SQL 2005性能计算器的值,实现对mssql的监控。详细的操作步骤和代码请参考附件。 ... [详细]
  • IOS开发之短信发送与拨打电话的方法详解
    本文详细介绍了在IOS开发中实现短信发送和拨打电话的两种方式,一种是使用系统底层发送,虽然无法自定义短信内容和返回原应用,但是简单方便;另一种是使用第三方框架发送,需要导入MessageUI头文件,并遵守MFMessageComposeViewControllerDelegate协议,可以实现自定义短信内容和返回原应用的功能。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 20211101CleverTap参与度和分析工具功能平台学习/实践
    1.应用场景主要用于学习CleverTap的使用,该平台主要用于客户保留与参与平台.为客户提供价值.这里接触到的原因,是目前公司用到该平台的服务~2.学习操作 ... [详细]
  • Go GUIlxn/walk 学习3.菜单栏和工具栏的具体实现
    本文介绍了使用Go语言的GUI库lxn/walk实现菜单栏和工具栏的具体方法,包括消息窗口的产生、文件放置动作响应和提示框的应用。部分代码来自上一篇博客和lxn/walk官方示例。文章提供了学习GUI开发的实际案例和代码示例。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • WhenIusepythontoapplythepymysqlmoduletoaddafieldtoatableinthemysqldatabase,itdo ... [详细]
author-avatar
无心伤害2502907297
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有