chat_client
module(chat_client).
-author(“Administrator”).
%% API
-export([start/0, login/2, reg/2,showuser/0, showroom/0,create_room/1,exit_room/0,join_room/1, send_msg/1, send_for/2, exit/0]).
-define(Port, 2345).
%%功能:登录/注册,创建/加入/退出房间,房间内公屏聊天,私聊,显示用户名/房间名/房间人数,退出账号
%%建立TCP连接,进程client打开一个和Server通信的套接字,建立ETS表用于存储用户信息
start() ->
register(client, spawn(fun() -> {ok, Socket} = gen_tcp:connect(“localhost”, ?Port, [binary, {packet, 4}]),
loop(Socket) end)),
ets:new(room, [public, set, named_table]),
ets:new(user, [public, set, named_table]),
{ok,please_login_or_register}.
%%%API函数
%%登录
login(ID, Password) ->
client ! {ID, Password, login}.
%%注册
reg(ID, Password) ->
client ! {ID, Password, register}.
%%显示房间
showroom()->
[{Roomname,Roomnumber}] = ets:tab2list(room),
io:format(“Room is pn”,[Roomname]),
io:format(“Numbers of room is pn”,[Roomnumber]).
%%显示用户名
showuser()->
[{ID,Socket}] = ets:tab2list(user),
io:format(“ID is:pn”,[ID]),
io:format(“Socket is:pn”,[Socket]).
%%创建房间
create_room(Roomname) ->
case ets:first(user) of
‘$end_of_table’ ->
io:format(“you must login first”);
_ ->
client ! {Roomname, create}
end.
%%加入房间
join_room(Room_name) ->
%%如果用户没登录
case ets:first(user) of
‘
e
n
d
o
f
t
a
b
l
e
′
−
>
i
o
:
f
o
r
m
a
t
(
"
y
o
u
m
u
s
t
l
o
g
i
n
f
i
r
s
t
"
)
;
−
>
c
a
s
e
e
t
s
:
f
i
r
s
t
(
r
o
o
m
)
o
f
′
end_of_table' -> io:format("you must login first"); _ -> case ets:first(room) of '
endoftable′−>io:format("youmustloginfirst");−>caseets:first(room)of′end_of_table’ ->
client ! {Room_name, join};
_ ->
%%如果用户已经在房间里面
io:format(“you are in another room”)
end
end.
%%退出房间
exit_room() ->
case ets:first(room) of
‘$end_of_table’ ->
io:format(“you must join room first”);
_ ->
Room_name = ets:first(room),
client ! {Room_name, exit_room}
end.
%%房间内公屏发送消息
send_msg(Msg) ->
case ets:first(user) of
‘
e
n
d
o
f
t
a
b
l
e
′
−
>
i
o
:
f
o
r
m
a
t
(
"
y
o
u
m
u
s
t
l
o
g
i
n
f
i
r
s
t
"
)
;
−
>
c
a
s
e
e
t
s
:
f
i
r
s
t
(
r
o
o
m
)
o
f
′
end_of_table' -> io:format("you must login first"); _ -> case ets:first(room) of '
endoftable′−>io:format("youmustloginfirst");−>caseets:first(room)of′end_of_table’ ->
io:format(“you must join room first”);
_ ->
client ! {Msg, msg}
end
end.
%%私聊
send_for(Msg, Who) ->
case ets:first(user) of
‘$end_of_table’ ->
io:format(“you must login first”);
_ ->
client ! {Msg, Who, one}
end.
%退出账号
exit() ->
case ets:first(user) of
‘$end_of_table’ ->
io:format(“you must login first”);
_ ->
Room_name = ets:first(room),
ID = ets:first(user),
client ! {Room_name, ID, closed}
end.
loop(Socket) ->
receive
{ID, Password, login} ->
gen_tcp:send(Socket, term_to_binary({ID, Password, login})),
receive
{tcp, _Socket, Bin} ->
CC = binary_to_term(Bin),
case CC of
login_succeed ->
ets:insert(user, {ID, Socket}),
io:format(“Receive : pn”, [CC]);
_ ->
io:format(“Receive : pn”, [CC])
end
end;
{ID, Password, register} ->
gen_tcp:send(Socket, term_to_binary({ID, Password, register})),
receive_loop();
{Msg, Roomname, msg} ->
gen_tcp:send(Socket, term_to_binary({Msg, Roomname, msg})),
receive_loop();
{Msg, Who, one} ->
gen_tcp:send(Socket, term_to_binary({Msg, Who, one})),
receive_loop();
{Roomname, create} ->
gen_tcp:send(Socket, term_to_binary({Roomname, create})),
receive_loop();
{Room_name, join} ->
gen_tcp:send(Socket, term_to_binary({Room_name, join})),
receive
{tcp, _Socket, Bin} ->
CC = binary_to_term(Bin),
case CC of
{join_succeed, Room_name, NewNumber} ->
ets:insert(room, {Room_name, NewNumber}),
io:format(“Receive : pn”, [CC]);
_ ->
io:format(“Receive : pn”, [CC])
end
end;
{Room_name, exit_room} ->
gen_tcp:send(Socket, term_to_binary({Room_name, exit_room})),
receive
{tcp, _Socket, Bin} ->
CC = binary_to_term(Bin),
case CC of
exit_succeed ->
ets:delete(room, Room_name),
io:format(“Receive : pn”, [CC]);
_ ->
io:format(“Receive : pn”, [CC])
end
end;
{Room_name, ID, closed} ->
gen_tcp:send(Socket, term_to_binary({Room_name, ID, closed})),
receive_loop();
{tcp, Socket, Bin} ->
AA = binary_to_term(Bin),
io:format(“Receive : pn”, [AA]);
{tcp_closed, Socket} ->
io:format(“closed now”)
end,
loop(Socket).
%%接收函数
receive_loop() ->
receive
{tcp, _Socket, Bin} ->
CC = binary_to_term(Bin),
io:format(“Receive : pn”, [CC])
end.
chat_server
-module(chat_server).
-author(“Administrator”).
-behaviour(gen_server).
%% API
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-define(Port, 2345).
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [2345], []).
init([Port]) ->
%%创建aony和nkss两个房间
%%创建login、register和room三个表记录user数据
ets:new(room, [public, set, named_table]),
ets:new(aony, [public, set, named_table]),
ets:new(nkss, [public, set, named_table]),
ets:new(register, [public, set, named_table]),
ets:insert(room, [{nkss, 0}, {aony, 0}]),
main_start(Port),
{ok, ets:new(login, [public, set, named_table])}.
%%创建并行服务器
main_start(Port) ->
{ok, Listen} = gen_tcp:listen(Port, [binary, {packet, 4}]),
spawn(fun() -> main_connect(Listen) end).
main_connect(Listen) ->
{ok, Socket} = gen_tcp:accept(Listen),
io:format(“connect succeed Socket = pn”, [Socket]),
spawn(fun() -> main_connect(Listen) end),
main(Socket).
main(Socket) ->
receive
{tcp, Socket, Bin} ->
Message = binary_to_term(Bin),
case Message of
{ID, Password, login} ->
login_handle(ID, Password, Socket);
{ID, Password, register} ->
register_handle(ID, Password, Socket);
{Msg, Roomname, msg} ->
send_handle(Msg, Socket, Roomname);
{Msg, Who, one} ->
one_for_one_handle(Msg, Who, Socket);
{Roomname, create} ->
create_handle(Roomname, Socket);
{Room_name, join} ->
join_handle(Room_name, Socket);
{Room_name, exit_room} ->
exit_room_handle(Room_name, Socket);
{Roomname, ID, closed} ->
closed_handle(Roomname, ID, Socket)
end
end,
main(Socket).
%%调用handle_call来处理客户端的需求
login_handle(ID, Password, Socket) ->
case gen_server:call(?MODULE, {ID, Password, Socket, login}) of
ok ->
gen_tcp:send(Socket, term_to_binary(login_succeed));
no ->
gen_tcp:send(Socket, term_to_binary(no_false))
end.
register_handle(ID, Password, Socket) ->
case gen_server:call(?MODULE, {ID, Password, register}) of
ok ->
gen_tcp:send(Socket, term_to_binary({ok, register_succeed}));
no ->
gen_tcp:send(Socket, term_to_binary({no, exist}))
end.
send_handle(Msg, Socket, Roomname) ->
List = ets:tab2list(Roomname),
AonyList = [X || {X, _Y} <- List],
gen_server:call(?MODULE, {Msg, Socket, AonyList, Roomname, msg}).
one_for_one_handle(Msg, Who, Socket) ->
gen_server:call(?MODULE, {Msg, Who, Socket, one_for_one}).
create_handle(Roomname, Socket) ->
gen_server:call(?MODULE, {Roomname, Socket, create}).
join_handle(Room_name, Socket) ->
case gen_server:call(?MODULE, {Room_name, Socket, join}) of
{ok, NewNumber} ->
gen_tcp:send(Socket, term_to_binary({join_succeed, Room_name, NewNumber}));
no ->
gen_tcp:send(Socket, term_to_binary(the_room_non_exitsent));
{no, you_are_in_room} ->
gen_tcp:send(Socket, term_to_binary({no, you_are_in_room}))
end.
exit_room_handle(Room_name, Socket) ->
gen_server:call(?MODULE, {Room_name, Socket, exit_room}).
closed_handle(Roomname, ID, Socket) ->
gen_server:call(?MODULE, {Roomname, ID, Socket, closed}).
%%% callbacks
%%% 处理客户端的需求
%%% 登录
handle_call({ID, Password, Socket, login}, _From, Tab) ->
Reply = case ets:lookup(register, ID) of
[{ID, Password}] ->
ets:insert(login, {ID, Socket}),
ok;
_ -> no
end,
{reply, Reply, Tab};
%% 注册
handle_call({ID, Password, register}, _From, Tab) ->
Reply = case ets:lookup(register, ID) of
[] ->
ets:insert(register, {ID, Password}),
ok;
_ -> no
end,
{reply, Reply, Tab};
%% 创建房间
handle_call({Roomname, Socket, create}, _From, Tab) ->
Reply = case ets:lookup(room, Roomname) of
[{Roomname, _Number}] ->
gen_tcp:send(Socket, term_to_binary({room_is_exist}));
_ ->
ets:new(Roomname, [public, set, named_table]),
ets:insert(room, {Roomname, 0}),
gen_tcp:send(Socket, term_to_binary({create_succeed}))
end,
{reply, Reply, Tab};
%% 加入房间
handle_call({Room_name, Socket, join}, _From, Tab) ->
Reply = case ets:lookup(room, Room_name) of
[{Room_name, RoomNumber}] ->
case ets:lookup(Room_name, Socket) of
[] ->
ets:insert(Room_name, {Socket, online}),
ets:insert(room, {Room_name, RoomNumber + 1}),
{ok, RoomNumber + 1};
[{Socket, online}] ->
{no, you_are_in_room}
end;
[] ->
no
end,
{reply, Reply, Tab};
%% 退出房间
handle_call({Room_name, Socket, exit_room}, _From, Tab) ->
Reply = case ets:lookup(room, Room_name) of
[{Room_name, RoomNumber}] ->
case ets:lookup(Room_name, Socket) of
[{Socket, online}] ->
ets:delete(Room_name, Socket),
ets:insert(room, {Room_name, RoomNumber - 1}),
gen_tcp:send(Socket, term_to_binary(exit_succeed));
[] ->
gen_tcp:send(Socket, term_to_binary(join_room_first))
end;
[] ->
gen_tcp:send(Socket, term_to_binary(no_this_room))
end,
{reply, Reply, Tab};
%% 退出账号
handle_call({Roomname, ID, Socket, closed}, _From, Tab) ->
Reply = case ets:lookup(login, ID) of
[{ID, Socket}] ->
ets:delete(login, ID),
[{Roomname, Number}] = ets:lookup(room, Roomname),
ets:insert(room, {Roomname, Number - 1}),
ets:delete(Roomname, Socket),
gen_tcp:send(Socket, term_to_binary(succeedexit));
_ ->
gen_tcp:send(Socket, term_to_binary(noexit))
end,
{reply, Reply, Tab};
%% 房间公屏聊天
handle_call({Msg, Socket, AonyList, Roomname, msg}, _From, Tab) ->
Reply = case ets:lookup(Roomname, Socket) of
[{Socket, online}] ->
lists:map(fun(E) -> gen_tcp:send(E, term_to_binary(Msg)) end, AonyList);
[] ->
gen_tcp:send(Socket, term_to_binary({no_in_room, Roomname}))
end,
{reply, Reply, Tab};
%% 私聊
handle_call({Msg, Who, Socket, one_for_one}, _From, Tab) ->
Reply = case ets:lookup(login, Who) of
[{Who, WhoSocket}] ->
gen_tcp:send(WhoSocket, term_to_binary(Msg)),
gen_tcp:send(Socket, term_to_binary(Msg));
[] ->
gen_tcp:send(Socket, term_to_binary(no_player_or_unonline))
end,
{reply, Reply, Tab}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
这是一个关于如何使用Erlang的OTP构建聊天室的示例。代码包括客户端(chat_client)和服务器端(chat_server)的功能,如登录、注册、创建/加入/退出房间、房间内聊天和私聊等操作。客户端通过TCP连接与服务器通信,并使用ETS表存储用户信息。服务器端负责处理客户端请求,如登录验证、房间管理等。

630

被折叠的 条评论
为什么被折叠?



