erlang学习: erlang版echoserver

本文介绍如何使用 Erlang 编程语言实现一个简单的回声服务器,利用 gen_tcp 模块和消息接收模型,每个连接对应一个独立的进程。
erlang实现的简单的echo server
采用每连接对应一个进程的模式
用到了 gen_tcp 模块、erlang的消息接收模型


-module(echoserver).

-export([start/0, stop/0, server/0, handle_connect/3]).

start() ->
% 创建一个进程,运行 server()
register(echoserver, spawn(?MODULE, server, [])).

stop() ->
echoserver ! {quit}.

server() ->
{ok, ListenSocket} = gen_tcp:listen(12345, [binary, {reuseaddr, true}, {active, false}]),
loop(ListenSocket, 0).

loop(ListenSocket, Count) ->
receive
{quit} ->
io:format("echoserver will stop~n"),
gen_tcp:close(ListenSocket);
Reason ->
io:format("recv ~p~n", Reason)
after 10 ->
% 等待连接
case gen_tcp:accept(ListenSocket, 3000) of
{ok, Socket} ->
% 创建一个进程来处理此连接
spawn(?MODULE, handle_connect, [Socket, [], Count]),
loop(ListenSocket, Count+1);
{error, timeout} ->
loop(ListenSocket, Count);
{error, Reason} ->
io:format("accept failed~n"),
gen_tcp:close(ListenSocket)
end
end.

handle_connect(Socket, BinaryList, Count) ->
io:format("handle_connect ~p~n", [self()]),
case gen_tcp:recv(Socket, 0) of
{ok, Binary} ->
case gen_tcp:send(Socket, Binary) of
ok ->
handle_connect(Socket, BinaryList, Count);
{error, Reason} ->
io:format("send failed~n"),
gen_tcp:close(Socket)
end;
{error, timeout} ->
io:format("recv timeout~n"),
gen_tcp:close(Socket);
{error, closed} ->
gen_tcp:close(Socket)
end.

### Erlang `gen_server` 使用教程 #### 创建一个简单的 `gen_server` 为了创建并使用 `gen_server`, 需要定义一个新的模块,该模块实现了 `gen_server` 行为。下面是一个基本的例子: ```erlang -module(myserver). -behaviour(gen_server). %% API. -export([start_link/0]). -export([echo/1]). %% gen_server callbacks. -export([init/1]). -export([handle_call/3]). -export([handle_cast/2]). -export([handle_info/2]). -export([terminate/2]). -export([code_change/3]). -record(state, {}). %%%=================================================================== %%% Spawning and Callbacks %%%=================================================================== start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). echo(Message) -> gen_server:call(?MODULE, {echo, Message}). init([]) -> {ok, #state{}}. handle_call({echo, Msg}, _From, State) -> Reply = Msg, {reply, Reply, State}; handle_call(_Request, _From, State) -> Reply = ok, {reply, Reply, State}. handle_cast(_Msg, State) -> {noreply, State}. handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, _State) -> ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. ``` 这段代码展示了如何构建一个最基础的服务,它能够接收消息并将其回显给调用者。 #### 解决常见问题 当遇到像 `gen_tcp:recv(Sock, 0)` 返回 `{error, einval}` 这样的错误时,这通常是因为尝试读取的数据长度参数不合理造成的[^2]。对于 TCP 接收操作来说,传入零作为数据量意味着立即返回而不会等待任何实际数据到来,这是不符合预期的行为。因此应该指定合理的正整数值或者不设置具体大小让其尽可能多地获取可用数据。 另外,在高负载情况下如果发现由于频繁发起 `gen_server:call` 导致性能下降,则可以考虑优化策略来减少同步请求的数量或是调整超时时间以适应实际情况。例如通过批量处理请求或将某些非关键性的任务改为异步执行模式(`gen_server:cast`)从而减轻服务器负担[^3]。 #### 实际应用中的注意事项 在开发基于 `gen_server` 的应用程序时还需要注意环境配置方面的问题,比如确保安装了正确的本以及必要的依赖库等[^1]。此外,编写健壮的应用程序还涉及到良好的状态管理和异常处理机制的设计。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值