【转载】erlang 中 socket 相关知识点

简介:
a. 最核心的概念 - socket 控制进程  
b. 基本的 C/S 结构的例子(服务器只能处理一个客户端连接)  
c. 顺序型服务器的例子(服务器顺序的处理客户端的请求,每次只能处理一个,处理完一个处理下一个)  
d. 并发型服务器的例子(服务器并发的处理多个客户端的请求)  
e. 控制逻辑 - 主动型消息接收(非阻塞  
f. 控制逻辑 - 被动型消息接收(阻塞  
g. 控制逻辑 - 混合型消息接收(半阻塞  

【最基本的 Erlang C/S 结构的例子】

  1. 创建一个 socket 进程(调用 gen_tcp:accept 或 gen_tcp:connect),也就是 socket 的控制进程,这个 socket 接收到的所有数据都转发给控制进程,如果控制进程消亡,socket 也会自行关闭,可以调用 gen_tcp:controlling_process(Socket, NewPid) 来把一个 socket 的控制进程改为新的进程。
  2. 服务器端客户端使用的 {packet, N} 的参数必须一致
  3. 在接收到一个连接的时候,显式的设置 socket 的属性,是一个好的策略。
?
1
2
{ok, Socket} = gen_tcp:accept(Listen),
inet:setopts(Socket, [{packet, 4}, {active, true }, {nodelay, true }])
Server 侧  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-module(server).
- export ([start /0 ]).
 
start() ->
     {ok, Listen} = gen_tcp:listen(2345, [binary, {packet, 4},
                                                  {reuseaddr, true },
                                                  {active, true }]),
     {ok, Socket} = gen_tcp:accept(Listen),
     gen_tcp:close(Listen),
     loop(Socket).
 
loop(Socket) ->
     receive
         {tcp, Socket, Bin} ->
             io: format ( "received: ~p~n" , [Bin]),
             gen_tcp:send(Socket, iolist_to_binary([ "server#" ,Bin])),
             loop(Socket);
         {tcp_closed, Socket} ->
             io: format ( "[~p] tcp_closed~n" , [Socket]);
         {tcp_error, Socket, Reason} ->
             io: format ( "[~p] tcp_error: ~p~n" , [Socket, Reason])
     end.
Client 侧  
?
1
2
3
4
5
6
7
8
9
10
11
-module(client).
- export ([ echo /1 ]).
 
echo (Data) ->
     {ok, Socket} = gen_tcp:connect( "localhost" , 2345, [binary, {packet, 4}]),
     ok = gen_tcp:send(Socket, Data),
     receive
         {tcp, Socket, Bin} ->
              io: format ( "~p~n" , [Bin]),
              gen_tcp:close(Socket)
     end.

【顺序型服务器的例子】

?
1
2
3
4
5
6
7
8
9
10
11
12
start() ->
     {ok, Listen} = gen_tcp:listen(2345, [binary, {packet, 4},
                                                  {reuseaddr, true },
                                                  {active, true }]),
     seq_accept(Listen).
 
seq_accept(Listen) ->
     {ok, Socket} = gen_tcp:accept(Listen),
     loop(Socket),
     seq_accept(Listen).
 
loop(Socket) … 不变
 

【并发型服务器的例子】

方式一  
?
1
2
3
4
5
6
7
8
9
10
11
12
start() ->
     {ok, Listen} = gen_tcp:listen(2345, [binary, {packet, 4},
                                                  {reuseaddr, true },
                                                  {active, true }]),
     spawn(fun() -> accept(Listen) end).
 
accept(Listen) ->
     {ok, Socket} = gen_tcp:accept(Listen),
     spawn(fun() -> accept(Listen) end),
     loop(Socket).
 
loop(Socket) … 不变
方式二  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
start() ->
     {ok, Listen} = gen_tcp:listen(2345, [binary, {packet, 4},
                                                  {reuseaddr, true },
                                                  {active, true }]),
     spawn(fun() -> accept(Listen) end).
 
accept(Listen) ->
     {ok, Socket} = gen_tcp:accept(Listen),
     Pid = spawn(fun() -> loop(Socket) end),
     gen_tcp:controlling_process(Socket, Pid),
     accept(Listen).
 
loop(Socket) … 不变

【控制逻辑】  
{active, true} – 主动 socket - 非阻塞模式  
      当数据到达系统之后,会向控制进程发送 {tcp, Socket, Data} 的消息,而控制进程无法控制 这些消息(的到来),一个独立的客户端可能向系统发送上万条消息,这些消息都会发送到控制进程,控制 进程无法通过控制停掉这些消息。  

{active, false} – 被动 socket - 阻塞模式  
      如果是被动 socket,则 socket 必须调用 gen_tcp:recv(Socket, N) 来接收数据,它尝试接收  N 字节的数据,如果 N 为 0,那么所有可用的字节都会返回。   默认是 gen_tcp:recv(Socket, N, infinity),即无限等待直到有数据可以接收,所以是 阻塞的模式。  

{active, once} – 半主动 socket  
      会创建一个主动 socket,可以主动接收一条消息,但该 socket 接收一条消息以后,如果打算让它接 收下一条消息,则必须重新激活它。   激活 Socket 的方式如下  
?
1
inet:setopts(Socket, [{active, once}])

【主动型接收 - 非阻塞模式- 异步服务器】  
?
1
2
3
4
5
6
7
8
9
10
11
{ok, Listen} = gen_tcp:listen( ..., {active, true }, ... ),
{ok, Socket} = gen_tcp:accept(Listen),
loop(Socket).
 
loop(Socket) ->
     receive
         {tcp, Socket, Data} ->
             ...;
         {tcp_closed, Socket} ->
             ...
     end.

【被动型接收 - 阻塞模式 – 同步服务器】  
?
1
2
3
4
5
6
7
8
9
10
11
12
{ok, Listen} = gen_tcp:listen( ..., {active, false }, ... ),
{ok, Socket} = gen_tcp:accept(Listen),
loop(Socket).
 
loop(Socket) ->
     case gen_tcp:recv(Socket, 0) of   %% 这里有说法
         {ok, Data} ->
             ...
             loop(Socket);
         {error, closed} ->
             ...
     end.

【混合型模式 - 半同步服务器】  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
{ok, Listen} = gen_tcp:listen( ..., {active, once}, ... ),
{ok, Socket} = gen_tcp:accept(Listen),
loop(Socket).
 
loop(Socket) ->
     receive
         {tcp, Socket, Data} ->
             ...
             inet:setopts(Socket, [{active, once}]),
             loop(Socket);
         {tcp_closed, Socket} ->
             ...
     end.

【socket 的出错处理】  
  • 每个 socket 都对应一个控制进程,如果控制进程消亡,则 socket 也会自动关闭;
  • 如果服务器端因为逻辑上的原因发生崩溃,那么服务器端的 socket 会自动关闭,同时客户端也会收到  {tcp_closed, Socket} 的消息。
目录
打赏
0
0
0
0
34
分享
相关文章
Erlang的socket 编程简例
版权声明:本文为半吊子子全栈工匠(wireless_com,同公众号)原创文章,未经允许不得转载。
1059 0
erlang web socket参考。
出自: http://blog.sina.com.cn/s/blog_96b8a15401010g71.html
619 0
erlang和java的socket通讯----最简单,初次实现。
直接上源码,留做纪念。 有点简单,大家不要笑,初次实现。 功能描述:java发送数据给erlang,erlang将收到的数据重复两次再发送给java。 erlang源码:模块tcp_listen -module(tcp_listen).
863 0
Erlang TCP Socket的接收进程的2种方案
转自:http://blog.csdn.net/summerhust/article/details/8740973   一旦打开了一个使用TCP连接的套接字,它就始终保持打开状态,直至任何一方关闭它或因为一个错误而终止。
1389 0
转载: Erlang Socket解析二进制数据包
转自:http://www.itkee.com/developer/detail-318.html 今天在家里闲来无事,实践了一下Erlang的Socket的功能。记录一下在过程中遇到的一些问题,以及编码的步骤。
1174 0
socket 通信 多线程调用窗体(委托)的几个知识点,记录在案,以备查阅
1.socket 通信传输汉字的方法:Encoding.GetEncoding("GB2312").GetString(Receivebyte) 发送接收都这样转化 直接上程序   public partial class Form1 : Form { pub...
840 0
深度探索Python Socket编程:从理论到实践,进阶篇带你领略网络编程的魅力!
【7月更文挑战第25天】在网络编程中, Python Socket编程因灵活性强而广受青睐。本文采用问答形式深入探讨其进阶技巧。**问题一**: Socket编程基于TCP/IP,通过创建Socket对象实现通信,支持客户端和服务器间的数据交换。**问题二**: 提升并发处理能力的方法包括多线程(适用于I/O密集型任务)、多进程(绕过GIL限制)和异步IO(asyncio)。**问题三**: 提供了一个使用asyncio库实现的异步Socket服务器示例,展示如何接收及响应客户端消息。通过这些内容,希望能激发读者对网络编程的兴趣并引导进一步探索。
111 4
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等