有这样一个问题,我们要获取一个5900~65535之间的一个端口号。对于这个端口号必须是唯一出现的,不能重复,如果分配出去的端口号使用完了之后,还要进行相应的回收,等待下一次的分配。要使用erlang来实现,这个该如何实现呢?
我是这么来实现的,在我的实现当中要使用mnesia数据库。每分配一个端口号出去之后,就将分配的端口号记录在数据库中,并且在数据库中使用一项记录下一次可以分配并且使用的端口号的值。如果下一次请求分配的时候,就直接读取分配出去的那个端口号,然后更新这一项,往数据库中添加已经分配的这个端口号,等下一次如果再次分配的时候,就直接分配。
我的程序代码如下:
- %% vncport.erl
- %% Author: Sunny
-
%% Created: 2011-7-25
-
%% Description: get vncport
-
-module(vncport).
-
-date("2011.07.25").
-
-
%%
-
%% Include Files
-
%%
-
-include_lib("stdlib/include/qlc.hrl").
-
-record(vnc_counter,
-
{
-
vncport_num,
-
used_flag
-
}).
-
-
%%
-
%% Exported Functions
-
%%
-
-export([init/0, stop/0]).
-
-export([recovery_one_vncport/1]).
-
-export([get_next_vncport/0]).
-
-
%%
-
%% Api Functions
-
%%
-
init() ->
- mnesia:stop(),
- mnesia:delete_schema([node()]),
- mnesia:create_schema([node()]),
- mnesia:start(),
- mnesia:create_table(vnc_counter,[{attributes, record_info(fields, vnc_counter)}]),
- F = fun(N) ->
- insert_to_table(N)
- end,
- for(5908, 5910, F),
- for(5915, 5917, F),
- mnesia:dirty_update_counter(vnc_counter, mac_id, 5900).
-
-
stop() ->
-
mnesia:stop().
-
-
get_next_vncport() ->
-
Query = qlc:q([X#vnc_counter.used_flag || X <- mnesia:table(vnc_counter),
-
X#vnc_counter.vncport_num =:= mac_id]),
-
F = fun() ->
-
qlc:e(Query)
-
end,
-
io:format("get the vncport which is not used~n"), %% degug info
-
{atomic, [Result]} = mnesia:transaction(F),
-
% spawn(fun() -> update_vnc_counter(Result) end),
-
update_vnc_counter(Result),
-
io:format("get the next vncport is:~p~n", [Result]), %% debug info
-
Result.
-
-
recovery_one_vncport(N) ->
-
Row = {vnc_counter, N},
-
F = fun() ->
-
mnesia:delete(Row)
-
end,
-
Result = mnesia:transaction(F),
-
io:format("delete ~p successfully~n", [N]), %% debug info
-
Result.
-
-
%%
-
%% Local Functions
-
%%
-
update_vnc_counter(X) ->
-
io:format("spawn one process to update vnc_counter~n"), %% debug info
-
insert_to_table(X),
-
io:format("add one used vncport to vnc_counter successfully!~n"), %% debug info
-
if
-
X+1 > 65535 ->
-
N=5900;
-
X+1 =< 65535 ->
-
N=X+1
-
end,
-
io:format("now begin check whether in vnc_counter~n"), %% debug info
-
case check_in_vnc_counter(N) of
-
true ->
-
io:format("find ~p is in vnc_counter~n", [N]), %% debug info
-
NX = find_not_in_vnc_counter(N), %% find one not in vnc_counter
-
Row = #vnc_counter{vncport_num=mac_id, used_flag=NX};
-
false ->
-
io:format("find ~p is not in vnc_counter~n", [N]), %% debug info
-
Row = #vnc_counter{vncport_num=mac_id, used_flag=N}
-
end,
-
F = fun() ->
-
mnesia:write(Row)
-
end,
-
mnesia:transaction(F),
-
io:format("update vnc_counter over~n"), %% debug info
-
ok.
-
-
check_in_vnc_counter(N) ->
-
io:format("check ~p is or not in vnc_counter~n", [N]), %% debug info
-
Query = qlc:q([X#vnc_counter.vncport_num || X <- mnesia:table(vnc_counter),
-
X#vnc_counter.vncport_num =:= N]),
-
F = fun() ->
-
qlc:e(Query)
-
end,
-
Result = mnesia:transaction(F),
-
io:format("check result is:~p~n", [Result]), %% debug info
-
case Result of
-
{atomic, []} ->
-
Return = false;
-
{atomic, [_]} ->
-
Return = true
-
end,
-
Return.
-
-
find_not_in_vnc_counter(N) ->
-
if
-
N+1 > 65535 ->
-
NX = 5900;
-
N+1 =< 65535 ->
-
NX = N+1
-
end,
-
case check_in_vnc_counter(NX) of
-
true ->
-
Result = find_not_in_vnc_counter(N+1);
-
false ->
-
Result = NX
-
end,
-
Result.
-
-
insert_to_table(N) ->
-
Row = #vnc_counter{vncport_num=N, used_flag=yes},
-
F = fun() ->
-
mnesia:write(Row)
-
end,
-
mnesia:transaction(F).
-
-
for(Max, Max, F) ->
-
[F(Max)];
-
for(Min, Max, F) ->
-
[F(Min)|for(Min+1, Max, F)].
这个程序的执行结果是:
- 1> c(vncport).
-
{ok,vncport}
-
2> vncport:init().
-
5900
-
3> vncport:get_next_vncport().
-
get the vncport which is not used
-
spawn one process to update vnc_counter
-
add one used vncport to vnc_counter
-
now begin check whether in vnc_counter
-
check 5901 is or not in vnc_counter
-
check result is:{atomic,[]}
-
find 5901 is not in vnc_counter
-
update vnc_counter over
-
get the next vncport is:5900
-
5900
-
4> vncport:get_next_vncport().
-
get the vncport which is not used
-
spawn one process to update vnc_counter
-
add one used vncport to vnc_counter
-
now begin check whether in vnc_counter
-
check 5902 is or not in vnc_counter
-
check result is:{atomic,[5902]}
-
find 5902 is in vnc_counter
-
check 5903 is or not in vnc_counter
-
check result is:{atomic,[5903]}
-
check 5904 is or not in vnc_counter
-
check result is:{atomic,[5904]}
-
check 5905 is or not in vnc_counter
-
check result is:{atomic,[5905]}
-
check 5906 is or not in vnc_counter
-
check result is:{atomic,[5906]}
-
check 5907 is or not in vnc_counter
-
check result is:{atomic,[5907]}
-
check 5908 is or not in vnc_counter
-
check result is:{atomic,[5908]}
-
check 5909 is or not in vnc_counter
-
check result is:{atomic,[5909]}
-
check 5910 is or not in vnc_counter
-
check result is:{atomic,[5910]}
-
check 5911 is or not in vnc_counter
-
check result is:{atomic,[]}
-
update vnc_counter over
-
get the next vncport is:5901
-
5901
-
5> vncport:get_next_vncport().
-
get the vncport which is not used
-
spawn one process to update vnc_counter
-
add one used vncport to vnc_counter
-
now begin check whether in vnc_counter
-
check 5912 is or not in vnc_counter
-
check result is:{atomic,[]}
-
find 5912 is not in vnc_counter
-
update vnc_counter over
-
get the next vncport is:5911
-
5911
-
6> vncport:get_next_vncport().
-
get the vncport which is not used
-
spawn one process to update vnc_counter
-
add one used vncport to vnc_counter
-
now begin check whether in vnc_counter
-
check 5913 is or not in vnc_counter
-
check result is:{atomic,[5913]}
-
find 5913 is in vnc_counter
-
check 5914 is or not in vnc_counter
-
check result is:{atomic,[5914]}
-
check 5915 is or not in vnc_counter
-
check result is:{atomic,[5915]}
-
check 5916 is or not in vnc_counter
-
check result is:{atomic,[5916]}
-
check 5917 is or not in vnc_counter
-
check result is:{atomic,[5917]}
-
check 5918 is or not in vnc_counter
-
check result is:{atomic,[]}
-
update vnc_counter over
-
get the next vncport is:5912
-
5912
-
7> vncport:get_next_vncport().
-
get the vncport which is not used
-
spawn one process to update vnc_counter
-
add one used vncport to vnc_counter
-
now begin check whether in vnc_counter
-
check 5919 is or not in vnc_counter
-
check result is:{atomic,[]}
-
find 5919 is not in vnc_counter
-
update vnc_counter over
-
get the next vncport is:5918
-
5918
-
8> vncport:get_next_vncport().
-
get the vncport which is not used
-
spawn one process to update vnc_counter
-
add one used vncport to vnc_counter
-
now begin check whether in vnc_counter
-
check 5920 is or not in vnc_counter
-
check result is:{atomic,[]}
-
find 5920 is not in vnc_counter
-
update vnc_counter over
-
get the next vncport is:5919
-
5919
-
9> vncport:get_next_vncport().
-
get the vncport which is not used
-
spawn one process to update vnc_counter
-
add one used vncport to vnc_counter
-
now begin check whether in vnc_counter
-
check 5921 is or not in vnc_counter
-
check result is:{atomic,[]}
-
find 5921 is not in vnc_counter
-
update vnc_counter over
-
get the next vncport is:5920
-
5920
-
10>
可能输出的信息比较多些,但是对于本程序来说我们只要关注最后的那个数据就行了。
在我的程序中有一个小的技巧就是在init()函数中使用的
mnesia:dirty_update_counter(vnc_counter, mac_id, 5900),
我使用了这个来记录下一次要读取的可以使用的数据,原先使用文件的记录,发现那是有问题的,而且在程序中处理数据库可以使用spawn一个进程,这个是可以的,但是我不知道使用是不是一件好的事情。
阅读(1208) | 评论(0) | 转发(0) |