-module(vpl).
-export([run/2]).
-define(IP, "127.0.0.1").
-define(PORT, 1777).
run(ThreadCount, MsgCount) ->
spawn_thread(-1, -1, ThreadCount, MsgCount).
spawn_thread(CurrentThreadNo, CurrentMsgNo, ThreadCount, MsgCount) ->
NewThreadNo = CurrentThreadNo + 1,
if
NewThreadNo == ThreadCount -> ok;
NewThreadNo < ThreadCount ->
RetryCount = 3,
spawn(fun() -> connect_vsp(NewThreadNo, MsgCount, RetryCount) end),
spawn_thread(NewThreadNo, CurrentMsgNo, ThreadCount, MsgCount)
end.
connect_vsp(ThreadNo, MsgCount, RetryCount) ->
case gen_tcp:connect(?IP, ?PORT, [binary]) of
{ok, Socket} ->
io:format("connect success! ThreadNo=~w~n", [ThreadNo]),
send_msg(Socket, MsgCount, 0, ThreadNo);
{error, Reason} ->
io:format("connect failed Error=~s,ThreadNo=~w~n!", [Reason, ThreadNo]),
NewRetryCount = RetryCount - 1,
if
NewRetryCount > 0 ->
io:format("reconnect ThreadNo=~w,RetryTime=~w~n", [ThreadNo, NewRetryCount]),
connect_vsp(ThreadNo, MsgCount, NewRetryCount);
NewRetryCount == 0 ->
io:format("reconnect ThreadNo=~w Reach Retry Max! ~n", [ThreadNo])
end
end.
send_msg(Socket, MsgCount, TransId, ThreadNo) ->
MsgContentBin = <<"TestContent">>,
Len = byte_size(MsgContentBin),
%% 封包頭:Len(32bit) | MsgType(16bit) | Version(16bit) | Reserve(32bit)
SendMsg = <> ++ MsgContentBin,
if
MsgCount == 0 ->
ok = gen_tcp:close(Socket),
io:format("test over ThreadNo=~w~n", [ThreadNo]);
MsgCount > 0 ->
case gen_tcp:send(Socket, SendMsg) of
ok -> receive_data(Socket, MsgCount-1, TransId+1, ThreadNo);
{error, Reason} -> io:format("send failed ~s~n!", [Reason])
end
end.
receive_data(Socket, MsgCount, TransId, ThreadNo) ->
receive
{tcp, Socket, Bin} ->
<> = Bin,
io:format("~w ~.16B ~n", [RecvLen, Bin]),
send_msg(Socket, MsgCount, TransId, ThreadNo);
{tcp_closed, Socket} ->
io:format("close~n")
end.
| 概念 | 說明 |
|---|---|
spawn/1 | 建立新輕量級程序,傳入零參數函式,回傳 PID。 |
gen_tcp:connect/3 | 建立 TCP 連線,選項 binary 以二進位制收發資料。 |
gen_tcp:send/2 | 發送二進位資料,同步阻塞直到發送完成或錯誤。 |
receive ... end | 訊息匹配區塊,依模式匹配處理 {tcp, Socket, Bin}、{tcp_closed, Socket}。 |
二進位語法 <<...>> | 構造/解構位元組序列,支援位元級欄位定義(如 Len:32)。 |
| 遞迴迴圈 | Erlang 無傳統迴圈,以尾遞迴實現狀態機(spawn_thread、send_msg、receive_data)。 |
| Len (4 bytes) | MsgType (2 bytes) | Version (2 bytes) | Reserve (4 bytes) | Payload (variable) |
發送端構造,接收端用模式匹配解析 RecvLen、MsgType,忽略其餘(_/binary)。