Erlang03_套接字编程(2) UDP

总篇:12

编辑于 2025/5/8 22:00

截稿于: 2025/5/8 23:30

上一篇实现了简单的TCP服务器客户端通信,接下来学习UDP

简介

Upd无需建立连接,因此无需listen,accept等操作,服务器只需要open一个Socket,然后无论谁都可以向其send数据,需要时也可手动close。

原语

gen_udp 模块:

  1. {ok,Socket} = open(Port,[binary])
{ok,Socket} = open(Port,[binary]),服务器监听Port端口(0是随机端口),数据以二进制形式传输
  1. ok =send(Socket,Host,Port,Bin)
ok =send(Socket,Host,Port,Bin), 服务器/客户端的Socket向Host,Port发送Bin数据包,
监听此端口的Socket接受到消息
  1. close(Socket)
close(Socket),关闭Socket,释放资源

简单的Udp通信

  1. 异步开启一个监听Port的服务器,监听到Port接受消息后打印,返回给客户端ok。
  2. 客户端随机监听一个端口打开Socket,向服务端端口发送消息,在接收到服务端返回的ok或者超时2s后,打印结果。
  3. 服务器的Socket没有关闭,可以继续生成客户端向其发送数据。
-module(socket_udp).
-export([start_server/1, client/2]).

start_server(Port) ->
    spawn(fun() -> server(Port) end).

server(Port) ->
    {ok, Socket} = gen_udp:open(Port, [binary]),
    loop(Socket).

loop(Socket) ->
    receive
        {udp, Socket, Host, Port, Bin} ->
            % 处理接收到的二进制数据
            Data = binary_to_term(Bin),
            io:format("received data: ~p~n", [Data]),
            BinReply = term_to_binary(ok),
            % 发送响应回客户端
            gen_udp:send(Socket, Host, Port, BinReply),
            loop(Socket)
    end.

client(Port, Request) ->
    {ok, Socket} = gen_udp:open(0, [binary]),
    ok = gen_udp:send(Socket, "localhost", Port, Request),
    Value =
        receive
            {udp, Socket, _, _, Bin} ->
                binary_to_term(Bin)
        after 2000 ->
            error
        end,
    % 关闭socket
    gen_udp:close(Socket),
    Value.

正常执行

error,因为没有监听1234端口的Socket,客户端无法得到回应

Udp因为其不保证消息可靠,可能会出现数据包丢失、错位。如果需要使用Udp来达到消息正确处理,需要用到"make_ref()", 该BIF会生成全球范围内唯一的一个引用Ref,充当详细的Id,客户端发送消息的时候携带Ref,服务端处理完消息后返回时也携带该Ref就能达到数据正确处理的效果。将以上代码改造:

  1. 客户端向服务端发送带Ref的数字
  2. 服务端接收到Ref和数子,返回Ref和数字的平方
  3. 客户端接收服务器发送的消息,只有Ref与其发送的Ref匹配的时候才接收,不同则error
-module(socket_udp).
-export([start_server/1, client/2]).

start_server(Port) ->
    spawn(fun() -> server(Port) end).

server(Port) ->
    {ok, Socket} = gen_udp:open(Port, [binary]),
    loop(Socket).

loop(Socket) ->
    receive
        {udp, Socket, Host, Port, Bin} ->
            {Ref, Number} = binary_to_term(Bin),
            Result = Number * Number,
            BinReply = term_to_binary({Ref, Result}),
            gen_udp:send(Socket, Host, Port, BinReply),
            loop(Socket)
    end.

client(Port, Number) when is_number(Number) ->
    {ok, Socket} = gen_udp:open(0, [binary]),
    Ref = make_ref(),
    Request = term_to_binary({Ref, Number}),
    ok = gen_udp:send(Socket, "localhost", Port, Request),
    Value =
        receive
            {udp, Socket, _, _, Bin} ->
                case binary_to_term(Bin) of
                    % 服务器返回的引用和客户端发送的应用匹配时才接收
                    {Ref, Result} -> Result;
                    _ -> {error, wrong_ref}
                end
        after 2000 ->
            {error, timeout}
        end,
    gen_udp:close(Socket),
    Value.

关于套接字先认识到这里。

posted on 2025-05-08 23:07  依只  阅读(8)  评论(0)    收藏  举报

导航