Erlang——嵌套字编程


套接字编程能让应用程序与互联网上的其他机器交互,比只进行本地操作有更大的空间。

套接字是一种通信信道,让不同的机器能用互联网协议(简称IP)在网上通信。

两个核心互联网协议:传输控制协议(简称TCP)和用户数据报协议(简称UDP)。

UDP能让应用程序相互发送简短的消息(称为数据报),但是并不保证这些消息能成功到达。
它们也可能会不按照发送顺序到达,更快但不可靠。

TCP能提供可靠的字节流,只要连接存在就会按顺序到达。用TCP发送数据的额外开销比用UDP发送数据更大,可靠但更慢。

套接字编程有两个主要的库:gen_tcp用于编写TCP应用程序,gen_udp用于编写UDP应用程序。

使用TCP

以一个简单的顺序型TCP服务器为例,会展示如何对应用程序的数据进行打包和编码。它接收一个请求,计算出一个回应,把回应送回,然后自行关闭。

从服务器上获取数据

代码演示(注意文件名称不能使用socket,会和系统内置模块名字冲突):

-module(socket1).
%%%=======================EXPORT=======================
-export([nano_get_url/0]).
nano_get_url() ->
  nano_get_url("www.baidu.com").
nano_get_url(Host) ->
  {
   ok, Socket} = gen_tcp:connect(Host, 80, [binary, {
   packet, 0}]),
  ok = gen_tcp:send(Socket, "GET / HTTP/1.0\r\n\r\n"),
  receive_data(Socket, []).

receive_data(Socket, SoFar) ->
  receive
    {
   tcp,Socket,Bin} ->
      receive_data(Socket, [Bin | SoFar]);
    {
   tcp_closed, Socket} ->
      list_to_binary(lists:reverse(SoFar))
  end.

(1)通过调用gen_tcp:connect,打开一个TCP套接字,它会连接到http://www.baidu.com的80端口上。连接调用的参数binary告诉系统,以binary模式打开套接字。在这个模式下,应用程序之间的数据传输都是二进制格式的。{packet,0}意味着Erlang系统会把TCP数据原封不动的直接传送给应用程序。
(2)通过调用 gen_tcp:send将GET / HTTP/1.0\r\n\r\n发送到套接字。之后等待回应。回应消息通常不会在一个数据包内全部返回,而是一帧一帧地返回,每帧一部分数据,程序以顺序行消息的方式收到这些数据帧,并把它转发给打开套接字的进程。
(3)程序会收到一个{tcp,Socket,Bin}消息。Bin是二进制类型,这就是我们为什么以二进制模型打开套接字。这个消息只是外部服务器发给程序的众多数据分之一,程序会把它添加到一个列表之中,这个列表汇聚程序目前接收到的所有数据,然后程序继续等待接收下一帧。
(4)当收到一个{tcp_closed, Socket}消息时,表明外部服务器已停止向程序发送消息。
(5)因为接收时我们是以错误的顺序来存储这些数据帧的,所以在所有的数据帧都接收完毕之后,需要调整顺序并拼接所有数据帧。

receive_data函数在数据帧到达时,程序只是简单的把数据帧加入列表SoFar的头部,程序接收完所有帧并且嵌套字也被关掉之后,程序再反转列表将它们拼接起来。

重整数据帧部分的代码,我们不用如下这种拼接的方式,因为要持续的向一个缓冲区中追加新的二进制数据,这个行为会产生很多无用的数据副本。

receive_data(Socket, SoFar) ->
  receive
    {
   tcp,Socket,Bin} ->
      receive_data(Socket, list_to_binary([SoFar,Bin]));
    {
   tcp_closed, Socket} ->
      SoFar
  end.

所以这是最好的方法:在一个列表中收集所有的数据帧,注意数据帧都添加完时顺序是逆序的,然后翻转整个列表,把所有数据在一个操作内拼接起来。

执行结果:

3> c(socket1).
{
   ok,socket1}
4> B = socket1:nano_get_url().
<<"HTTP/1.0 200 OK\r\nAccept-Ranges: bytes\r\nCache-Control: no-cache\r\nContent-Length: 9508\r\nContent-Type: text/html\r\nDate:"...>>
5> io:format("~p~n",[B]).    
<<72,84,84,80,47,49,46,48,32,50,48,48,32,79,75,13,10,65,99,99,101,112,116,45,
  ...
  47,104,116,109,108,62>>
6> string:tokens(binary_to_list(B),"\r\n").
["HTTP/1.0 200 OK","Accept-Ranges: bytes",
 "Cache-Control: no-cache","Content-Length: 9508",
 "Content-Type: text/html",
 "Date: Wed, 20 Sep 2023 15:04:03 GMT",
 "P3p: CP=\" OTI DSP COR IVA OUR IND COM \"",
 "P3p: CP=\" OTI DSP COR IVA OUR IND COM \"",
 "Pragma: no-cache","Server: BWS/1.1",
 "Set-Cookie: BAIDUID=3F53CD0CD1E0D2C394D1256F08954962:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.b
aidu.com",
 "Set-Cookie: BIDUPSID=3F53CD0CD1E0D2C394D1256F08954962; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu
.com",
 "Set-Cookie: PSTM=1695222243; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com",
 "Set-Cookie: BAIDUID=3F53CD0CD1E0D2C326284A0E92F9B1AD:FG=1; max
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值