Erlang02_并发编程(4) 基于套接字的分布式模式

总篇:10

编辑于 2025/5/6 20:30

截稿于: 2025/5/6 22:10

简介

套接字(Socket),IP+Port,连接两台终端设备的“插槽”,使用套接字主要是为了相互可信的设备连通。

原语

gen模块:

  1. {ok,ListenSocket} =listen(Port [

    binary,

    {packet, 0},

    {active, true},

]) 启动服务器

listen(Port [        % 端口号
    binary,             % 以二进制形式处理数据
    {packet, 0},        % 原始数据模式,不自动处理包长度
    {active, true},     % 主动模式,自动将数据转为消息发送给进程
    {reuseaddr, true}   % 允许重用地址,快速重启服务器
])
在Port启动一个服务
  1. {ok,Socket} =connect("localhost", ServerPort, [

     binary,
    
     {packet, 0},
    
     {active, true}
    

    ]) 客户第连接服务器

connect(
    "localhost",      % 主机地址
    ServerPort,       % 服务器端口号
    [
        binary,       % 以二进制形式处理数据
        {packet, 0},  % 原始数据模式
        {active, true}% 主动模式
    ]
)
返回的是{ok,Socket实例}
  1. accept(ClientSocket)
 {ok, Socket} = accept(ClientSocket),
  1. send(Socket, term_to_binary(Data)) 消息发送
send(Socket, term_to_binary(Data))
通过Socket发送消息,客户端向服务器发送,以二进制数据的形式发送。

聊天室修改为套接字

-module(chat_server).
-export([start/1]).

start(Port) ->
    {ok, ListenSocket} = gen_tcp:listen(Port, [binary, {packet, 0}, 
                                              {active, true}, 
                                              {reuseaddr, true}]),
    io:format("Chat server started on port ~p~n", [Port]),
    acceptor(ListenSocket, #{}).

acceptor(ListenSocket, Clients) ->
    {ok, Socket} = gen_tcp:accept(ListenSocket),
    spawn(fun() -> acceptor(ListenSocket, Clients) end),
    loop(Socket, Clients).

loop(Socket, Clients) ->
    receive
        {tcp, Socket, <<"REGISTER:", Name/binary>>} ->
            io:format("New client registered: ~p~n", [Name]),
            NewClients = maps:put(Socket, Name, Clients),
            loop(Socket, NewClients);
            
        {tcp, Socket, Data} ->
            case maps:get(Socket, Clients, undefined) of
                undefined ->
                    io:format("Message from unregistered client: ~p~n", [Data]),
                    loop(Socket, Clients);
                Name ->
                    broadcast_message(Name, Data, maps:to_list(Clients)),
                    loop(Socket, Clients)
            end;
            
        {tcp_closed, Socket} ->
            case maps:get(Socket, Clients, undefined) of
                undefined -> ok;
                Name -> io:format("Client ~p disconnected~n", [Name])
            end,
            NewClients = maps:remove(Socket, Clients),
            loop(Socket, NewClients);
            
        Other ->
            io:format("Received unknown message: ~p~n", [Other]),
            loop(Socket, Clients)
    end.

broadcast_message(From, Message, ClientList) ->
    io:format("Broadcasting message from ~p: ~p~n", [From, Message]),
    lists:foreach(fun({Socket, _Name}) -> 
        gen_tcp:send(Socket, <<From/binary, ":", Message/binary>>)
    end, ClientList).

-module(chater).
-export([start/3, send_message/2]).

start(Name, Host, Port) ->
    case gen_tcp:connect(Host, Port, [binary, {packet, 0}, {active, true}]) of
        {ok, Socket} ->
            % 首先发送注册消息
            Registration = <<"REGISTER:", Name/binary>>,
            gen_tcp:send(Socket, Registration),
            Pid = spawn(fun() -> loop(Name, Socket) end),
            {ok, Pid, Socket};
        {error, Reason} ->
            {error, Reason}
    end.

send_message(Socket, Message) when is_binary(Message) ->
    gen_tcp:send(Socket, Message);
send_message(Socket, Message) ->
    gen_tcp:send(Socket, term_to_binary(Message)).

loop(Name, Socket) ->
    receive
        {tcp, Socket, Data} ->
            io:format("~p Received message: ~p~n", [Name, Data]),
            loop(Name, Socket);
        {tcp_closed, Socket} ->
            io:format("~p: Server closed connection~n", [Name]),
            exit(normal);
        {tcp_error, Socket, Reason} ->
            io:format("~p: TCP Error: ~p~n", [Name, Reason]),
            exit(Reason)
    end.

以上程序存在以下问题:
消息只能发送给服务端,客户端无法接受其他客户端发送来的消息

posted on 2025-05-06 22:08  依只  阅读(12)  评论(0)    收藏  举报

导航