【问题标题】:Erlang TCP server handlingErlang TCP 服务器处理
【发布时间】:2023-03-07 05:25:01
【问题描述】:

我开始学习 Erlang,希望为实时多人游戏创建游戏服务器。目前,我正在尝试估计 Erlang 与 Scala 相比会造成的工作量和头痛。所以,首先,我正在创建一个简单的 Erlang 服务器进程。我找到了Jesse Farmer 的一个很好的教程,我已经对其进行了修改以了解更多信息。我修改后的代码类似于他的回显服务器,除了它接受英文单词并简单地返回 Lojban 等价物。但是,只会选择通配符大小写。代码如下:

-module(translate).
-export([listen/1]).
-import(string).

-define(TCP_OPTIONS, [binary, {packet, 0}, {active, false}, {reuseaddr, true}]).

% Call echo:listen(Port) to start the service.
listen(Port) ->
    {ok, LSocket} = gen_tcp:listen(Port, ?TCP_OPTIONS),
    accept(LSocket).

% Wait for incoming connections and spawn the echo loop when we get one.
accept(LSocket) ->
    {ok, Socket} = gen_tcp:accept(LSocket),
    spawn(fun() -> loop(Socket) end),
    accept(LSocket).

% Echo back whatever data we receive on Socket.
loop(Socket) ->
    case gen_tcp:recv(Socket, 0) of
        {ok, Data} ->
            case Data of
                "Hello" -> gen_tcp:send(Socket, "coi\n");
                "Hello\n" -> gen_tcp:send(Socket, "coi\n");
                'Hello' -> gen_tcp:send(Socket, "coi\n");
                <<"Hello">> -> gen_tcp:send(Socket, "coi\n");
                <<"Hello\n">> -> gen_tcp:send(Socket, "coi\n");
                _ -> gen_tcp:send(Socket, "I don't understand")
            end,
            loop(Socket);
        {error, closed} ->
            ok
    end.

我目前的测试是打开两个终端窗口并执行

[CONSOLE 1]
erl
c(translate).
translate:listen(8888).

[CONSOLE 2]
telnet localhost 8888
whatever
Hello

然后输出变成:

I don't understand
I don't understand

如何解析传入的数据?这种模式匹配的风格似乎完全失败了。谢谢!

【问题讨论】:

    标签: tcp erlang


    【解决方案1】:

    试试这个:

    case binary_to_list(Data) of
        "Hello\r\n" -> gen_tcp:send(Socket, "this will be good variant\n");
        _ -> gen_tcp:send(Socket, "I don't understand")
    end,
    

    或者没有显式转换:

    case Data of
        <<"Hello\r\n">> -> gen_tcp:send(Socket, "this will be good variant\n");
        _ -> gen_tcp:send(Socket, "I don't understand")
    end,
    

    从 cmets 更新

    要处理更复杂的匹配,请先删除 "\r\n" 后缀:

    Content = list_to_binary(lists:subtract(binary_to_list(Data), "\r\n")),
    case Content of
        <<"Hello">> -> gen_tcp:send(Socket, <<"Good day!\n">>);
        <<"My name is, ", Name/binary>> -> gen_tcp:send(Socket, <<"Hello ", Name/binary, "!\n">>);
        _ -> gen_tcp:send(Socket, "I don't understand")
    end,
    

    【讨论】:

    • 惊人的!这似乎工作得很好。在此之后,我将如何从传入的数据包中提取信息?我试过&lt;&lt;"My name is ", Name, "\r\n"&gt;&gt; -&gt; gen_tcp:send(Socket, "Hello " ++ Name ++ "!\n")之类的东西,但它也从来没有遇到过这种情况。
    • @Grimless 两个错误: 1. 在这里匹配Name 的正确方法:&lt;&lt;"My name is ", Name:10/binary, "\r\n"&gt;&gt; 其中10Name 长度(在任何情况下您都应该指定长度以进行非剩余匹配)。我知道,这不是你真正想要的 :) 所以首先尝试拆分 Data (以 Name 将二进制的最后一部分)。 2."Hello " ++ Name ++ "!\n" 会失败。这不是:&lt;&lt;"Hello ", Name/binary, "!\n"&gt;&gt;(或者如果您想使用列表 "Hello " ++ binary_to_list(Name) ++ "!\n" - 但对于简单操作来说操作太多)。
    • 嗯,"Hello " ++ Name ++ "!\n" 似乎编译得很好,但它可能不会导致问题,因为该子句从未执行过。我将如何“首先拆分Data”?我无法保证输入名称的长度,那么Name:10/binary如何处理The Duke of All The World等输入?此外,将代码更改为&lt;&lt;"My name is ", Name:10/binary, "\r\n"&gt;&gt; -&gt; gen_tcp:send(Socket, string:join(["mi'o ", Name, "\r\n"], "")); 仍然不起作用。
    • 太棒了!虽然此时 Erlang 感觉非常笨重和陈旧,但我认识到它所呈现的思想和范式非常优雅。感谢您的帮助!
    猜你喜欢
    • 2015-06-09
    • 1970-01-01
    • 2013-12-07
    • 2010-11-27
    • 2018-01-28
    • 2011-02-20
    • 1970-01-01
    • 1970-01-01
    • 2021-04-20
    相关资源
    最近更新 更多