实现一个大容量、高并发的tcp代理,模拟移动网络报文延迟的情况

       测试移动互联网应用时,因为现实的网络中,延迟非常严重,而实验环境很难出现延迟,比如ssl连接时,在实验室很难出现握手很慢的情况。而直接现网验证风险很大,心里没底

       所以在网络中增加一个tcp proxy,终端连接到proxy,proxy连接到服务端,在proxy中人为的随机延迟报文。所有基于TCP的协议都可以使用这个代理,比如http、ssl等。


开发的难度、并发要求等情况考虑,使用erlang是一个比较合适的选择。

下面是代码,c(tcp_proxy).后,运行

tcp_proxy:start(客户端连接的端口, "192.168.9.145", 服务端的端口).

然后终端连接“客户端连接的端口”,每建一个连接,代理都起一个独立的进程,连接到服务端,然后终端服务端之间转发报文,不做任何解析。

在process中,可以延迟,也可以丢包,甚至可以改写报文。



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

-module(tcp_proxy).

-export([
    start/3,
    server/3,
    process/1,
    loop/2
]).

start(LPort, DHost, DPort) ->
    case gen_tcp:listen(LPort,[{active, true},{packet,raw}]) of
        {ok, ListenSock} ->
            spawn(?MODULE, server, [ListenSock, DHost, DPort]),
            {ok, Port} = inet:port(ListenSock),
            Port;
        {error,Reason} ->
            {error, Reason}
    end
.

%% tcp_proxy:start(客户端连接的端口, "192.168.9.145", 服务端的端口).

server(LSocket, DHost, DPort) ->
    io:format("Server started ~n"),
    case gen_tcp:accept(LSocket) of
        {ok, SrcSocket} ->
            io:format("Got connect ~n"),
            case gen_tcp:connect(DHost, DPort, [binary, {packet,raw}, {active, true}]) of
            {ok, DstSocket} ->
                io:format("Connect to dest server ~n"),
                Pid = spawn_link(fun() -> loop(SrcSocket, DstSocket) end),
                gen_tcp:controlling_process(DstSocket, Pid),
                gen_tcp:controlling_process(SrcSocket, Pid);
                
            E ->
                io:format("Error:Connect failed!~n"),
                E
            end,
            
            ok;
        
        Other ->
            io:format("Error: accept returned ~w - finita!~n",[Other]),
            ok
    end,
    
    server(LSocket, DHost, DPort)
.

loop(SrcSocket, DstSocket) ->
    %% inet:setopts(SrcSocket, [{active,once}]),
    receive
        {tcp, SrcSocket, Data} ->
            %%Len = length(Data),
            %%io:format("Received tcp(SrcSocket,~p) ~p ~n",[Len, Data]),
            case process(Data) of % you can poke around with the data
                {ok, RetData} ->
                    %%io:format("Send to tcp(DstSocket,~p) ~p ~n",[Len, RetData]),
                    gen_tcp:send(DstSocket, RetData);
                error ->
                    io:format("discarded~n"),
                    ok
            end,
            loop(SrcSocket, DstSocket); % erlang awesomeness. no loops ;)
            
        {tcp, DstSocket, Data} ->
            %%Len = size(Data),
            %%io:format("Received tcp(DstSocket,~p) ~p ~n", [Len, Data]),
            case process(Data) of % you can poke around with the data
                {ok, RetData} ->
                    %%io:format("Send to tcp(SrcSocket,~p) ~p ~n",[Len, RetData]),
                    gen_tcp:send(SrcSocket, RetData);
                error ->
                    io:format("discarded~n"),
                    ok
            end,
            loop(SrcSocket, DstSocket);

        {tcp_closed, SrcSocket} ->
            gen_tcp:close(DstSocket),
            io:format("DstSocket ~w closed [~w]~n",[SrcSocket,self()]),
            ok;
            
        {tcp_closed, DstSocket}->
            gen_tcp:close(SrcSocket),
            io:format("DstSocket (SrcSocket) ~w closed [~w]~n",[SrcSocket,self()]),
            ok
    end
.

%% 改这里,模拟不同的网络环境,当前实现50%的情况下,报文会延迟0-10秒
process(Data) ->
    R = random:uniform(100),
    if
        R > 50 ->
            timer:sleep(random:uniform(10000)),
            {ok, Data};
        true ->
            {ok, Data}
    end
.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值