erlang聊天室

服务端

点击查看代码
%%%-------------------------------------------------------------------
%%% @author wujj
%%% @copyright (C) 2021, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 08. 8月 2021 13:33
%%%-------------------------------------------------------------------
-module(chatserv).
-author("wujj").

%% API
-compile(export_all).
-import(ets, [insert_new/2]).

start_server() ->
  ets:new(id, [ordered_set, public, named_table, {write_concurrency, true}, {read_concurrency, true}]),
  case gen_tcp:listen(1234, [binary, {packet, 0}, {active, true}]) of
    {ok, ListenSocket} ->
      spawn(fun() -> client_connect(ListenSocket) end);
    {error, Reason} ->
      io:format("~p~n", [Reason])
  end.


client_connect(ListenSocket) ->
  case gen_tcp:accept(ListenSocket) of
    {ok, Socket} ->
      %% 进行验证,看是否是注册还是登录
      spawn(fun() -> client_connect(ListenSocket) end),
      loop(Socket);
    {error, Reason} ->
      io:format("~p~n", [Reason])
  end.

loop(Socket) ->
  receive
    {tcp, Socket, Bin} ->
      [Id, Sign, PassWord, SendId, MessageInfos] = binary_to_term(Bin),
      if
        Sign =:= register_user ->
          Info = register_user(Id, PassWord, Socket),
          gen_tcp:send(Socket, term_to_binary(Info)),
          loop(Socket);
        Sign =:= login_user ->
          Info = login_user(Id, PassWord, Socket),
          gen_tcp:send(Socket, term_to_binary(Info)),
          loop(Socket);
        Sign =:= login_out ->
          Info = login_out(Id, Socket),
          gen_tcp:send(Socket, term_to_binary(Info)),
          loop(Socket);
        Sign =:= private_msg ->
          private_chat(SendId, Socket, MessageInfos),
          loop(Socket);
        Sign =:= group_msg ->
          group_chat(Socket, MessageInfos),
          loop(Socket);
        true ->
          io:format("error sign ~n"),
          loop(Socket)
      end;
    {tcp_closed, Socket} ->
      io:format("Server socket closed ~n")
  end.

%% 用户注册
register_user(Id, PassWord, Socket) ->
  case ets:lookup(id, Id) of
    [_Ok] ->
      io:format("Account is fail ~n"),
      "Account is exist ~n";
    _ ->
      ets:insert(id, {Id, PassWord, 0, Socket}),
      "register successed ~n"
  end.

%% 用户登录
login_user(Id, PassWord, Socket) ->
  case ets:match_object(id, {Id, PassWord, 0, Socket}) of
    [_Ok] ->
      ets:update_element(id, Id, [{3, 1}, {4, Socket}]),
      "login successed";
    Reson ->
      io:format("login is fail ~n ~p", [Reson]),
      "Password error or Account is not exist ~n"
  end.

%% 退出用户
login_out(Id, Socket) ->
  %% 因为id对应唯一socket,所以不需要PassWord
  case ets:match_object(id, {Id, '_', 1, Socket}) of
    [_Ok] ->
      ets:update_element(id, Id, [{3, 0}, {4, 0}]),
      "login successed";
    _ ->
      io:format("out is fail ~n"),
      "login is fail"
  end.

%% 群聊
group_chat(Socket, MessageInfos) ->
  case ets:match_object(id, {'_', '_', 1, Socket}) of
    [{Id, _, _, _}] ->
      Res = ets:match_object(id, {'_', '_', 1, '_'}),
      case Res =:= [] of
        true ->
          io:format("no person online ~p ~n", [Res]);
        _ ->
          group_send_msg(Res, Id, MessageInfos)
      end;
    _ ->
      io:format("group chat is fail ~n")
  end.


%% 群聊发送
group_send_msg([], _Id, _MessageInfos) ->
  next;
group_send_msg([Info | Infos], Id, MessageInfos) ->
  {_, _, _, Socket} = Info,
  gen_tcp:send(Socket, term_to_binary("from: " ++ integer_to_list(Id) ++ "say: " ++ MessageInfos)),
  group_send_msg(Infos, Id, MessageInfos).

%% 在线私聊
private_chat(SendId, Socket, MessageInfos) ->
  case ets:match_object(id, {'_', '_', 1, Socket}) of
    [{Id, _, _, _}] ->
      Res = ets:match_object(id, {SendId, '_', 1, '_'}),
      case Res =:= [] of
        true ->
          io:format("send person not online ~p ~n", [Res]);
        _ ->
          private_send_msg(Res, Id, MessageInfos)
      end;
    _ ->
      io:format("private chat is fail ~n")
  end.

%% 私聊发送
private_send_msg([Info], Id, MessageInfos) ->
  {_, _, _, Socket} = Info,
  gen_tcp:send(Socket, term_to_binary("from: " ++ integer_to_list(Id) ++ "say: " ++ MessageInfos)).

客户端
点击查看代码
%%%-------------------------------------------------------------------
%%% @author wujj
%%% @copyright (C) 2021, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 08. 8月 2021 14:03
%%%-------------------------------------------------------------------
-module(chatclient).
-author("wujj").

%% API
-compile(export_all).

%客户端
start_client() ->
  {ok, Socket} = gen_tcp:connect("localhost", 1234, [binary, {packet, 0}]),  %连接服务器
  %新建一个进程负责接收消息
  Pid = spawn(fun() -> loop() end),
  gen_tcp:controlling_process(Socket, Pid),
  sendMsg(Socket).

loop() ->
  receive
    {tcp, _Socket, Bin} ->
      Res = binary_to_term(Bin),
      io:format("Message Info! ~p ~n", [Res]),
      loop();
    {tcp_closed, _Socket} ->
      io:format("Socket is closed! ~n")
  end.

sendMsg(Socket) ->
  S = io:get_line("select operation: "),
  {Sign, _Info} = string:to_integer(S),
  SendMsg = operation_message(Sign),
  gen_tcp:send(Socket, term_to_binary(SendMsg)),
  sendMsg(Socket).

%% 用户注册
operation_message(1) ->
  I = io:get_line("id: "),
  {Id, _Info} = string:to_integer(I),
  Password = io:get_line("register password: "),
  [Id, register_user, Password, 0, 0];
%% 用户登录
operation_message(2) ->
  I = io:get_line("id:"),
  Password = io:get_line("login password: "),
  {Id, _Info} = string:to_integer(I),
  [Id, login_user, Password, 0, 0];
%% 用户退出
operation_message(3) ->
  I = io:get_line("id: "),
  {Id, _Info} = string:to_integer(I),
  [Id, login_out, 0, 0, 0];
%% 私聊
operation_message(4) ->
  Sd = io:get_line("send_id: "),
  Msg = io:get_line("MsgInfo: "),
  {SendId, _Info} = string:to_integer(Sd),
  [0, private_msg, 0, SendId, Msg];
%% 群聊
operation_message(5) ->
  Msg = io:get_line("MsgInfo: "),
  [0, group_msg, 0, 0, Msg];
%% 无效操作
operation_message(_) ->
  Msg = io:format("invalid_operation ~n"),
  [0, invalid_operation, 0, 0, Msg].

posted @ 2024-06-25 01:02  酷i  阅读(29)  评论(0)    收藏  举报