复制前文的应对方法概览:
1从大道理上来讲,需要开发者预估一个进程的处理能力,不要向进程投递过多的消息以致于处理不完,如果处理不完,则需要重新设计,将消息分布到多个进程中处理;
2将异步接收消息的进程与调用port(receive_match)的模式的进程分开;
3拆分向port投递命令的过程,由进程来接收port回传的结果,而不是由模块接收;
4不使用port编写的模块,利用nif重新实现一套;
5其它。
这里介绍套接字发送的场景。
对于1,这确实是一个使用广泛的大道理,能解决一切,却好像又什么都没有解决,开发者需要不断摸索才能做到,我还在摸索中,所以就再次略过;
对于2,前文已经介绍过思路和优缺点,此处也就不再赘述;
对于3,rabbitmq已经给出了实现范例,我在开发过程中也借用了过来:
rabbit_writer.erl
handle_message({send_command, MethodRecord}, State) ->
ok = internal_send_command_async(MethodRecord, State),
State;
internal_send_command_async(MethodRecord,
#wstate{sock = Sock,
channel = Channel,
protocol = Protocol}) ->
ok = port_cmd(Sock, assemble_frame(Channel, MethodRecord, Protocol)).
internal_send_command_async(MethodRecord, Content,
#wstate{sock = Sock,
channel = Channel,
frame_max = FrameMax,
protocol = Protocol}) ->
ok = send_frames(fun port_cmd/2, Sock, assemble_frames(Channel, MethodRecord, Content, FrameMax, Protocol)).
port_cmd(Sock, Data) ->
true = try rabbit_net:port_command(Sock, Data)
catch error:Error -> exit({writer, send_failed, Error})
end,
ok.
rabbit_net.erl
port_command(Sock, Data) when ?IS_SSL(Sock) ->
case ssl:send(Sock#ssl_socket.ssl, Data) of
ok -> self() ! {inet_reply, Sock, ok},
true;
{error, Reason} -> erlang:error(Reason)
end;
port_command(Sock, Data) when is_port(Sock) ->
erlang:port_command(Sock, Data).
上述是第一阶段的port_command。
rabbit_writer.erl
handle_message({inet_reply, _, ok}, State) ->
State;
handle_message({inet_reply, _, Status}, _State) ->
exit({writer, send_failed, Status});
上述是第二阶段的receive过程,其中{inet_reply, Socket, Status}为gen_tcp:send发送命令后,receive到的消息。
套接字发送不存在文件写遇到的2个问题,首先,套接字发送过程的任何错误不会影响进程状态,因为发送者只有在收到应用层的确认时,才会认为消息到达,没有确认则可以认为未到达;其次,套接字接收消息可以通过在连接时使用{active,once/true}选项,令对端的数据直接投递到接收进程内部,而不需要显式调用gen_tcp:recv,也就不存在消息紊乱的问题;
对于4,我目前还没有找到实现,但是由于网络连接随时可以断开,进程也必须收到连接断开的异步通知,因此必须要使用消息机制异步通知进程,因此完全通过nif实现套接字访问是不可接受的,幸运的是,3已经足够解决问题了;
对于5,在通过gen_tcp:connect连接时,可以设置一个选项为delay_send,该选项类似于文件打开的delayed_write选项,在gen_tcp:send进入port_driver时,首先将要写的数据缓存到套接字port的发送缓存中,此时可以令
gen_tcp:send迅速返回,从而加快处理速度,减少进程消息队列堆积量,但该方法终有瓶颈,不能无限制应对消息增加,且为了更好的异步发送性能,需要配合另外一个选项nodelay,但这样会牺牲一部分同步发送性能;
套接字发送的解决方法较少,但是却很实用,向rabbitmq的编写者们致敬!
实际项目开发时,异步服务器的编写会时常碰到,读者们也会遇到这些问题,期待大家更好的解决方法!
分享到:
相关推荐
本人出于学习目的仿照CAsyncSocket原理封装的一个可独立处理消息的异步套接字CTSSocket类,与Client和Server端为一体的异步TCP流式套接字。
异步套接字的服务器端与客户端,效率高,打开Task Manager测试运行时效率。
基于SocketAsyncEventArgs的异步套接字通讯框架 基于SocketAsyncEventArgs的异步套接字通讯框架 基于SocketAsyncEventArgs的异步套接字通讯框架 基于SocketAsyncEventArgs的异步套接字通讯框架
异步socket套接字服务端实例案例代码,很好用的案例代码。
线程同步与异步套接字编程 线程同步与异步套接字编程线程同步与异步套接字编程
对异步套接字原理进行了解写了通信测试代码用来了解
易语言同步异步套接字模块源码,同步异步套接字模块,Call,取字节集指针,异步客户_初始,异步客户_销毁,异步客户_连接,异步客户_断开,异步客户_发送数据,异步客户_取回数据,异步客户_回调函数,同步客户_初始,同步客户_...
同步和异步的套接字模块源码
异步套接字服务器加客户端
使用VC++异步套接字类(AsyncSocket),进行“异步非阻塞”客户/服务器(Client/Server)网络程序设计的方法与原理。
深入了解异步套接字
本实例实现了简单的异步套接字传输 ,包括客户端与服务器端,适合初学者学习异步传输
异步套接字详细代码详解,有助于初学者学习
易语言原始套接字应用源码,原始套接字应用,显示信息,窗口消息处理,数据到达,异步通讯安装,异步通讯卸载,异步选择,异步处理,异步返回,UnHOOK,HOOKFunc,HOOKAPI,GetFunc,changefunc,CallFunc,数值_无符号_短整数,内存_...
异步socket套接字客户端实例案例代码,基于TCP,源代码,很好的案例代码
基于tcp的异步套接字客户端服务端通信,需要的就下载吧 1分不多哦
基于c/s的异步网络通信,有服务器,客户端,WSAAsyncSelect,客户端连接服务器,可以进行相互的通信
自己仿照别人写的一个聊天程序,网络结构类似 P2P的集中式索引服务器 结构 先启动服务器 然后启动多个客户端,多个客户端之间可以进行异步套接字通信。