其实也不能算是我的了,是我去年从mochiweb里扣出来的最最最基本的TCP通信代码, mochiweb是一个开源的高并发HTTP服务器,据说可以打造百万级应用。 mochiweb 有上万行,我抠出来只有百多行,算是够精简的了,现在贴出来,方便像我一样的菜鸟学习,造福人类。其实也是方便我自己,放硬盘上估计过段时间就找不到了。很久没有看这语言了,改不动,所以特别感谢北京-CS帮我修改了错误。
功能很简单,就是收到什么数据,就发送什么数据,可以作为很好的入门代码,就不解释那么多了,直接贴代码:
my_server模块如下:
- -module(my_server).
- -export([start/0, stop/0, looper/1]).
- %这个Options我本来打算从配置文件里读取,然后组装成一个record,但是不大熟,所以这里没有用到它
- %以后用得上再改
- -define(Options, [
- {port, 8442},
- {loop, {?MODULE, loop}},
- {name, ?MODULE}
- ]).
- -record(qiao_socket_server,
- {port=8024,
- loop,
- name,
- ip=any,
- nodelay=false,
- backlog=128,
- listen=null,
- active_sockets=0}
- ).
- start() ->
- %%socket_server:start(?Options).
- socket_server:start(#qiao_socket_server{loop = {?MODULE, looper}}).
- stop() ->
- socket_server:stop(?Options).
- %关闭服务的我也没有改,所以这里有个错误。
- looper(Socket) ->
- inet:setopts(Socket, [{active, once}]),
- receive
- {tcp, Socket, Data} ->
- io:format("Got packet: ~p~n", [Data]), %接收到什么数据,就发生什么数据
- gen_tcp:send(Socket, Data),
- looper(Socket);
- {tcp_closed, Socket}->
- io:format("Socket ~p closed~n", [Socket]);
- {tcp_error, Socket, Reason} ->
- io:format("Error on socket ~p reason: ~p~n", [Socket, Reason])
- end.
socket_server模块代码如下:
- -module(socket_server).
- -author('huanghongqiao').
- -behaviour(gen_server).
- -export([start/0,start/1, stop/1]).
- -export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3,
- handle_info/2]).
- -define(RECBUF_SIZE, 8192).
- -record(qiao_socket_server,
- {port=8024,
- loop,
- name,
- ip=any,
- nodelay=false,
- backlog=128,
- listen=null,
- active_sockets=0}
- ).
- %%客户端函数, start 开启服务,stop 关闭服务
- start() ->
- gen_server:start(?MODULE, [], []).
- start(InitArg = #qiao_socket_server{name = Name}) ->
- case Name of
- undefined ->
- gen_server:start(?MODULE, InitArg, []);
- _ ->
- gen_server:start(Name, ?MODULE, InitArg, [])
- end.
- stop(Name) when is_atom(Name) ->
- gen_server:cast(Name, stop);
- stop(Pid) when is_pid(Pid) ->
- gen_server:cast(Pid, stop);
- stop(State = #qiao_socket_server{name = Name}) ->
- stop(Name).
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- %% 回调函数
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- init(State = #qiao_socket_server{ip=Ip, port=Port, backlog=Backlog, nodelay=NoDelay}) ->
- BaseOpts = [binary,
- {reuseaddr, true},
- {packet, 0},
- {backlog, Backlog},
- {recbuf, ?RECBUF_SIZE},
- {active, false},
- {nodelay, NoDelay}],
- listen(Port, BaseOpts, State). %%监听
- handle_call(_Msg, _Caller, State) -> {noreply, State}.
- handle_info(_Msg, Library) -> {noreply, Library}.
- terminate(Reason, #qiao_socket_server{listen=Listen}) ->
- io:format("socket close,~p~n",[Reason]),
- gen_tcp:close(Listen). %%关闭Listen
- code_change(_OldVsn, State, _Extra) ->
- State.
- handle_cast({accepted, Pid}, State=#qiao_socket_server{active_sockets=ActiveSockets,
- listen = Listen, loop = Loop}) ->
- NewState = State#qiao_socket_server{active_sockets=1 + ActiveSockets},
- socket_server_acceptor:start_link(self(), Listen, Loop),
- {noreply, NewState}.
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- listen(Port, Opts, State) ->
- case gen_tcp:listen(Port, Opts) of
- {ok, Listen} ->
- socket_server_acceptor:start_link(self(), Listen, State#qiao_socket_server.loop),
- NewState = State#qiao_socket_server{listen = Listen},
- {ok, NewState};
- {error, Reason} ->
- {stop, Reason}
- end.
socket_server_acceptor模块代码如下:
- -module(socket_server_acceptor).
- -export([start_link/3, init/3]).
- start_link(Server, Listen, Loop) ->
- proc_lib:spawn_link(?MODULE, init, [Server, Listen, Loop]).
- init(Server, Listen, Loop) ->
- case catch gen_tcp:accept(Listen) of
- {ok, Socket} ->
- gen_server:cast(Server, {accepted, self()}),
- io:format("socket init,~p~n", [self()]),
- call_loop(Loop, Socket);
- {error, closed} ->
- io:format("socket close,~n"),
- exit(normal);
- {error, timeout} ->
- io:format("socket timeout"),
- init(Server, Listen, Loop);
- {error, esslaccept} ->
- io:format("socket close2,~n"),
- exit(normal);
- R ->
- io:format("socket close1,~p~n",[R]),
- exit({error, accept_failed})
- end.
- call_loop({M, F}, Socket) ->
- io:format("socket call_loop,~n"),
- M:F(Socket);
- call_loop({M, F, [A1]}, Socket) ->
- M:F(Socket, A1);
- call_loop({M, F, A}, Socket) ->
- erlang:apply(M, F, [Socket | A]);
- call_loop(Loop, Socket) ->
- Loop(Socket).
运行效果见下图,具体能支持多少并发,我也没有测试过,哈哈:
转载于:https://blog.51cto.com/huanghongqiao/1124450