Erlang中有没有类似于unix下的IO多路复用机制

发布于 2022-09-03 10:39:48 字数 3789 浏览 20 评论 1

一个unix程序希望从多个文件描述符中读取数据,直接使用read系统调用去处理有可能会阻塞在一个文件描述符上,而不能处理其他的文件描述符,因此系统提供了select系统调用对多个文件描述符进行监测。

在erlang系统中也存在类似的问题,如果process既需要读文件又需要接收消息,该如何处理了?当然最简单的方法是创建一个新的process,原有的process执行IO阻塞操作,新的process执行接收消息的阻塞操作。不知道Erlang中有没有类似于unix下的IO多路复用机制,使用一个process就可以监测两个信号源。

具体以下面的chat server例子来说,程序中的main process执行accept操作,client_manager process执行client集合的管理操作,我希望main process能够和client manager process合并,这样可以简化程序的逻辑。

多谢回答。

  1. -module(basicchat).
  2. -export([listen/1]).
  3. %% 侦听socket的 TCP 选项。第一个 list 元语
  4. %% 表示我们想接收数据的是字节列表(如
  5. %% 字符串),而不是二进制的对象。
  6. %% 其他的参数请参考 Erlang 文档。
  7. -define(TCP_OPTIONS,[list, {packet, 0}, {active, false}, {reuseaddr, true}]).
  8. %% 侦听指定的端口,接受第一个连接,
  9. %% 然后启动 echo 循环。同时要启动 client_manager,
  10. %% 这个是服务器的入口点。
  11. listen(Port) ->
  12.     Pid = spawn(fun() -> manage_clients([]) end),
  13.     register(client_manager, Pid),
  14.     {ok, LSocket} = gen_tcp:listen(Port, ?TCP_OPTIONS),
  15.     do_accept(LSocket).
  16. %% 接受以后创建处理过程,
  17. %% 末尾调用 do_accept 再次进入侦听
  18. %% 还要通知 client_manager 有新的连接要加入
  19. do_accept(LSocket) ->
  20.     {ok, Socket} = gen_tcp:accept(LSocket),
  21.     spawn(fun() -> handle_client(Socket) end),
  22.     client_manager ! {connect, Socket},
  23.     do_accept(LSocket).
  24. %% handle_client/1 替换掉 do_echo/1 ,因为现在所有事情都要
  25. %% 通过 client_manager 完成。断开时通知 client_manager
  26. %% socket 已经关闭,数据就当是发送完成了。
  27. handle_client(Socket) ->
  28.     case gen_tcp:recv(Socket, 0) of
  29.         {ok, Data} ->
  30.             client_manager ! {data, Data},
  31.             handle_client(Socket);
  32.         {error, closed} ->
  33.             client_manager ! {disconnect, Socket}
  34.     end.
  35. %% 维护 socket 列表,处理连接和断开消息,
  36. %% 并互相传递数据
  37. manage_clients(Sockets) ->
  38.     receive
  39.         {connect, Socket} ->
  40.             io:fwrite("Socket connected: ~w~n", [Socket]),
  41.             NewSockets = [Socket | Sockets];
  42.         {disconnect, Socket} ->
  43.             io:fwrite("Socket disconnected: ~w~n", [Socket]),
  44.             NewSockets = lists:delete(Socket, Sockets);
  45.         {data, Data} ->
  46.             send_data(Sockets, Data),
  47.             NewSockets = Sockets
  48.     end,
  49.     manage_clients(NewSockets).
  50. %% 给列表中的所有 socket 发消息。通过 lists:foreach/2 遍历
  51. %% 列表中的每个 socket,再调用 gen_tcp:send 来发送数据
  52. send_data(Sockets, Data) ->
  53.     SendData = fun(Socket) ->
  54.                        gen_tcp:send(Socket, Data)
  55.                end,
  56.     lists:foreach(SendData, Sockets).

复制代码

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

往事随风而去 2022-09-04 16:24:36

小弟初学erlang,?TCP_OPTIONS之前的?代表什么意思?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文