作为新手的练习项目,使用erlang来实现一个聊天室是一个很好的练手形式,接下来讲解下我开发过程的思路和根据需求变化的版本的迭代升级.
初代版本1.0
对于聊天室的需求有以下几点:
1)用户登录
2)所有登陆的用户默认在大厅中,可以进行聊天
2)房间创建,创建者自动成为房主
3)进入房间,同一个房间里的人可以聊天
4)退出房间,当所有人退出房间时,10秒内若是没有人进入该房间,则房间销毁,若是期间有人进入,则自动升级为该房房主
5)房主具有禁言,解禁,踢人,过让房主权限
对于上述的最基本的需求,我使用了tcp并行连接,ets表存储信息,定义功能号等,最初始的开发模板是在另一个博客中找到的最为基础的版本,仅仅是实现了登录与消息发送功能.因为后面进行了数据存储方式和结构的改进,所以对于这一版本仅仅贴上一些代码
chat_client.erl
%%初始化
init([]) ->
get_socket(),
{ok, ets:new(mysocket, [public, named_table])}.
%获取socket
get_socket() ->
register(client, spawn(fun() -> {ok, Socket} = gen_tcp:connect("localhost", 2345, [binary, {packet, 0}]),
handle(Socket) end)).
%<<-------------------------回调函数----------------------------->>
%登录的时候添加socket
handle_cast({addSocket, UserName, Socket}, Tab) ->
case ets:lookup(Tab, UserName) of
[{UserName, Socket}] -> have_socket;
[] -> ets:insert(Tab, {UserName, Socket})
end,
{noreply, Tab}.
%<<-------------------------回调函数----------------------------->>
%登录接口
login(Name, Password) ->
% io:format("log1 ~p ~p ~n ",[Name,Password]),
client ! {self(), {login, Name, Password}},
receive
Response -> Response
end.
%聊天发送接口
send_message(Msg) ->
client ! {self(), {msg, Msg}},
receive
Response -> Response
end.
%------------------------------------------------
handle(Socket) ->
receive
%来自控制进程的请求
{From, Request} ->
case Request of
%登录的请求协议号0000
{login, Name, Password} ->
N = term_to_binary(Name),
P = term_to_binary(Password),
Packet = <<0000:16, (byte_size(N)):16, N/binary, (byte_size(P)):16, P/binary>>,
%定义前4个字节为协议号,名字字节长度占4字节,然后时名字字节,然后是密码字节长度占4字节,最后是密码字节
gen_tcp:send(Socket, Packet),
receive
{tcp, Socket, Bin} ->
<<State:16, Date/binary>> = Bin, %状态码
<<Size1:16, Date1/binary>> = Date, %登录成功信息长度
case binary_to_term(Date1) of