一個簡單的TCP服務器


1.只接收一個連接然后自動關閉的服務端代碼

 1 -module(socket_server).
 2 
 3 -export([start_nano_server/0]).
 4 
 5 start_nano_server() ->
 6     % 監聽來自端口2345上的連接,消息打包規則{packet, 4} -> 每個應用程序都是從一個4字節長的頭部開始
 7     % gen_tcp:listen -> {ok, ListenSocket} | {error, Reason}, ListenSocket為監聽套接字 
 8     {ok, ListenSocket} = gen_tcp:listen(2345, [binary, {packet, 4},
 9                                         {reuseaddr, true},
10                                         {active, true}]),
11     % gen_tcp:accept(Listensocket)調用時,程序會暫停並等待一個連接
12     % 當一個新的連接建立起來時會返回變量Socket,該變量綁定到新建連接的套接字上
13     % 通過Socket套接字,服務器就可以和發起連接的客戶機進行通信
14     {ok, Socket} = gen_tcp:accept(ListenSocket),
15     % 關閉監聽套接字,此后服務器不會繼續處於監聽狀態,也無法建立新的連接,但並不影響已經建立的連接套接字
16     % 只是阻止新連接的建立
17     gen_tcp:close(ListenSocket),
18     loop(Socket).
19 
20 loop(Socket) ->
21     receive
22         {tcp, Socket, Bin} ->
23             io:format("Server received binary = ~p~n", [Bin]),
24             Str = binary_to_term(Bin),  % 對接收數據解碼(反整編)
25             io:format("Server(unpacked) ~p~n", [Str]),
26             Reply = lib_misc:string2value(Str),     % 對回應數據進行編碼(整編)
27             io:format("Server replying = ~p~n", [Reply]),
28             % send(Socket, Packet) -> ok | {error, Reason}, Packet -> iodata()
29             gen_tcp:send(Socket, term_to_binary(Reply)),
30             loop(Socket);
31         {tcp_closed, Socket} ->
32             io:format("Server socket closed~n")
33     end.

2.順序型服務器

 1 %% 順序型服務器
 2 -module(socket_server_order).
 3 
 4 -export([start_nano_server/0]).
 5 
 6 start_nano_server() ->
 7     % 監聽來自端口2345上的連接,消息打包規則{packet, 4} -> 每個應用程序都是從一個4字節長的頭部開始
 8     % gen_tcp:listen -> {ok, ListenSocket} | {error, Reason}, Listen為監聽套接字 
 9     {ok, ListenSocket} = gen_tcp:listen(2345, [binary, {packet, 4},
10                                         {reuseaddr, true},
11                                         {active, true}]),
12     req_loop(ListenSocket).
13 
14 req_loop(ListenSocket) ->
15     {ok, Socket} = gen_tcp:accept(ListenSocket),
16     loop(Socket),
17     req_loop(ListenSocket).
18 
19 loop(Socket) ->
20     receive
21         {tcp, Socket, Bin} ->
22             io:format("Server received binary = ~p~n", [Bin]),
23             Str = binary_to_term(Bin),
24             io:format("Server(unpacked) ~p~n", [Str]),
25             Reply = lib_misc:string2value(Str),
26             io:format("Server replying = ~p~n", [Reply]),
27             gen_tcp:send(Socket, term_to_binary(Reply)),
28             loop(Socket);
29         {tcp_closed, Socket} ->
30             io:format("Server socket closed~n")
31     end.

3.並發型服務器

 1 %% 並發型服務器
 2 -module(socket_server_order).
 3 
 4 -export([start_nano_server/0]).
 5 
 6 start_nano_server() ->
 7     % 監聽來自端口2345上的連接,消息打包規則{packet, 4} -> 每個應用程序都是從一個4字節長的頭部開始
 8     % gen_tcp:listen -> {ok, ListenSocket} | {error, Reason}, Listen為監聽套接字 
 9     {ok, ListenSocket} = gen_tcp:listen(2345, [binary, {packet, 4},
10                                         {reuseaddr, true},
11                                         {active, true}]),
12     spawn(fun() -> par_connect(ListenSocket) end).
13 
14 par_connect(ListenSocket) ->
15     {ok, Socket} = gen_tcp:accept(ListenSocket),
16     spawn(fun() -> par_connect(ListenSocket) end),
17     loop(Socket).
18 
19 loop(Socket) ->
20     receive
21         {tcp, Socket, Bin} ->
22             io:format("Server received binary = ~p~n", [Bin]),
23             Str = binary_to_term(Bin),
24             io:format("Server(unpacked) ~p~n", [Str]),
25             Reply = lib_misc:string2value(Str),
26             io:format("Server replying = ~p~n", [Reply]),
27             gen_tcp:send(Socket, term_to_binary(Reply)),
28             loop(Socket);
29         {tcp_closed, Socket} ->
30             io:format("Server socket closed~n")
31     end.

4.客戶端代碼

 1 -module(socket_client).
 2 
 3 -export([nano_client_eval/1]).
 4 
 5 nano_client_eval(Str) ->
 6     {ok, Socket} = gen_tcp:connect("localhost", 2345,
 7                                     [binary, {packet, 4}]),
 8     ok = gen_tcp:send(Socket, term_to_binary(Str)),
 9     receive
10         {tcp, Socket, Bin} ->
11             io:format("Client received binary = ~p~n", [Bin]),
12             Val = binary_to_term(Bin),
13             io:format("Client result = ~p~n", [Val]),
14             gen_tcp:close(Socket)
15     end.

5.lib_misc模塊

1 -module(lib_misc).
2 
3 -export([string2value/1]). 
4 
5 string2value(L) -> string2value(L, []).
6 string2value([], N)    -> list_to_tuple(lists:reverse(N));
7 string2value([H|T], N) -> string2value(T, [H|N]).

 6.測試

  6.1只接收一個連接然后自動關閉的服務端代碼測試

 

  6.2順序型服務器測試

 

 6.3並發型測試

 

ps:順序型服務器相對並發型服務器的區別在於:順序型服務器忙於服務一個現存的連接時,如果又有新的客戶機嘗試連接服務器,那么這個連接就會在服務器排隊,直到服務器完成對現有的服務為止,如果等待隊列中的連接數目超過了監聽套接字的能力,那么這個連接就會被拒絕,而並發型服務器則不會有該問題


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM