TCP半开的几个测试,比较简单都在Erlang Shell中完成.立此存照,备忘.
gen_tcp提供了shutdown来实现这个功能,下面官方文档中提到了{exit_on_close,false}参数,如果要实现半开,无论是Read Write都要添加这个参数. 官网文档 Doc Ref

shutdown(Socket, How) -> ok | {error, Reason}

Types:

Socket = socket()
How = read | write | read_write
Reason = posix()
Immediately close a socket in one or two directions.

How == write means closing the socket for writing, reading from it is still possible.

To be able to handle that the peer has done a shutdown on the write side, the {exit_on_close, false} option is useful.

shutdown read

%% ServerEshell V5.9  (abort with ^G)
1>  {ok,S0}=gen_tcp:listen(5678,[]).
{ok,#Port<0.506>}
2> {ok,S2}=gen_tcp:accept(S0).
{ok,#Port<0.512>}
3> flush().
Shell got {tcp,#Port<0.512>,[104,105,44,121,111,117,32,104,97,118,101,32,110,101,119,32,109,115,103,32,0]}
ok
4> gen_tcp:shutdown(S2,read).
ok
5> flush().
Shell got {tcp_closed,#Port<0.512>}
ok
6> gen_tcp:send(S2,"are you alive?").
{error,closed}
7>%% ClientEshell V5.9  (abort with ^G)
1> {ok,S1}= gen_tcp:connect("localhost",5678,[]).
{ok,#Port<0.511>}
2> gen_tcp:send(S1,"hi,you have new msg \0").
ok
3> gen_tcp:send(S1,"hi,you have new msg \0").  %% 发送这条消息导致server端 接受到tcp_closed的消息
ok
4> gen_tcp:send(S1,"hi,you have new msg \0").  %% 服务器端宕掉之后再发送消息 Client也会出现{error,closed}错误
{error,closed}

Client添加一下选项 {exit_on_close, false} 试试
%% ServerEshell V5.9  (abort with ^G)
1>  {ok,S0}=gen_tcp:listen(5678,[]).
{ok,#Port<0.506>}
2>  {ok,S2}=gen_tcp:accept(S0).
{ok,#Port<0.512>}
3>  gen_tcp:send(S2,"are you alive?").
ok
4> flush().
Shell got {tcp,#Port<0.512>,[104,105,44,121,111,117,32,104,97,118,101,32,110,101,119,32,109,115,103,32,0]}
ok
5> gen_tcp:shutdown(S2,read).
ok
6>  inet:getstat(S2).  %%这时候检查一下Socket的状态
{ok,[{recv_oct,21},{recv_cnt,1},{recv_max,21},{recv_avg,21},{recv_dvi,0},{send_oct,14},{send_cnt,1},{send_max,14},{send_avg,14},{send_pend,0}]}
7>  gen_tcp:send(S2,"are you alive?====").  %% 由于server只关闭了read 所以发送消息还可以发送出去
ok
8> flush().                   %% Client尝试发送消息
Shell got {tcp_closed,#Port<0.512>}
ok
9>  inet:getstat(S2).
{error,einval}
10>%% ClientEshell V5.9  (abort with ^G)
1>  {ok,S1} = gen_tcp:connect("localhost",5678,[{exit_on_close, false} ]).
{ok,#Port<0.511>}
2> gen_tcp:send(S1,"hi,you have new msg \0").
ok
3> flush().
Shell got {tcp,#Port<0.511>,"are you alive?"}
ok
4> flush().                     %% 服务器端只关闭了read 还可以发送消息 这条消息还可以收到
Shell got {tcp,#Port<0.511>,"are you alive?===="}
ok
5> gen_tcp:send(S1,"hi,you have new msg \0").  %% Client向Server发送消息 会导致Server收到tcp_closed消息
ok
6> gen_tcp:send(S1,"hi,you have new msg \0").
{error,closed}
7>

shutdown write

下面的测试关注点是shutdown write,过程和上面类似:
%%ServerEshell V5.9  (abort with ^G)
1>  {ok,S0}=gen_tcp:listen(5678,[]).
{ok,#Port<0.506>}
2> {ok,S2}=gen_tcp:accept(S0).
{ok,#Port<0.512>}
3> flush().
Shell got {tcp,#Port<0.512>,[104,105,44,121,111,117,32,104,97,118,101,32,110,101,119,32,109,115,103,32,0]}
ok
4>  gen_tcp:send(S2,"are you alive?").
ok
5> gen_tcp:shutdown(S2,write). %% 执行完这一句 检查Socket已经是einval
ok
6>  inet:getstat(S2).
{error,einval}
7>%%ClientEshell V5.9  (abort with ^G)
1>  {ok,S1}= gen_tcp:connect("localhost",5678,[]).
{ok,#Port<0.511>}
2> gen_tcp:send(S1,"hi,you have new msg \0").
ok
3> flush().
Shell got {tcp,#Port<0.511>,"are you alive?"}
ok
4> gen_tcp:send(S1,"hi,you have new msg \0").
{error,closed}
5>

调整实验 添加exit_on_close选项 
%%ServerEshell V5.9  (abort with ^G)
1> {ok,S0}=gen_tcp:listen(5678,[]).
{ok,#Port<0.506>}
2>  {ok,S2}=gen_tcp:accept(S0).
{ok,#Port<0.512>}
3> flush().
Shell got {tcp,#Port<0.512>,[104,105,44,121,111,117,32,104,97,118,101,32,110,101,119,32,109,115,103,32,0]}
ok
4>  gen_tcp:send(S2,"are you alive?").
ok
5> gen_tcp:shutdown(S2,write).
ok
6>   inet:getstat(S2).  %% 对比上面的测试结果 这里是正常的状态
{ok,[{recv_oct,21},{recv_cnt,1},{recv_max,21},{recv_avg,21},{recv_dvi,0},{send_oct,14},{send_cnt,1},{send_max,14},{send_avg,14},{send_pend,0}]}
7> flush().                %% 由于只关闭了写,读还是正常的,接受到的消息
Shell got {tcp,#Port<0.512>,[104,105,44,121,111,117,32,104,97,118,101,32,110,101,119,32,109,115,103,32,50,32,0]}
ok
8>  gen_tcp:send(S2,"are you alive?").  %% 关闭了写  这里的调用就会报错了
{error,closed}
9>   inet:getstat(S2).
{error,einval}
10>%% ClientEshell V5.9  (abort with ^G)
1>  {ok,S1} = gen_tcp:connect("localhost",5678,[{exit_on_close, false} ]).
{ok,#Port<0.511>}
2>  gen_tcp:send(S1,"hi,you have new msg \0").
ok
3> flush().
Shell got {tcp,#Port<0.511>,"are you alive?"}
ok
4>  gen_tcp:send(S1,"hi,you have new msg 2 \0").
ok
5>

gen_tcp shutdown

看看gen_tcp 的shutdown的逻辑:
shutdown(S, How) when is_port(S) ->case inet_db:lookup_socket(S) of{ok, Mod} ->Mod:shutdown(S, How);Error ->Errorend.

 inet_db:lookup_socket(S) 的结果是什么?在Shell里面测试一下:
Eshell V5.9  (abort with ^G)
1>  {ok,S0}=gen_tcp:listen(5678,[]).
{ok,#Port<0.506>}
2> inet_db:lookup_socket(S0).
{ok,inet_tcp}
3>

|-->  inet_tcp

%%
%% Shutdown one end of a socket
%%
shutdown(Socket, How) ->prim_inet:shutdown(Socket, How).

|--> prim_inet.erl
shutdown(S, read) when is_port(S) ->shutdown_2(S, 0);
shutdown(S, write) when is_port(S) ->shutdown_1(S, 1);
shutdown(S, read_write) when is_port(S) ->shutdown_1(S, 2).shutdown_1(S, How) ->case subscribe(S, [subs_empty_out_q]) of{ok,[{subs_empty_out_q,N}]} when N > 0 ->shutdown_pend_loop(S, N);   %% wait for pending output to be sent_Other -> okend,shutdown_2(S, How).shutdown_2(S, How) ->case ctl_cmd(S, ?TCP_REQ_SHUTDOWN, [How]) of{ok, []} -> ok;{error,_}=Error -> Errorend.shutdown_pend_loop(S, N0) ->receive{empty_out_q,S} -> okafter ?INET_CLOSE_TIMEOUT ->case getstat(S, [send_pend]) of{ok,[{send_pend,N0}]} -> ok;{ok,[{send_pend,N}]} -> shutdown_pend_loop(S, N);_ -> okendend.

上面处理考虑的相当周全,如果shutdown的时候有消息还没有发送完成,就会先完成暂存数据的发送,霸爷有一篇很详细的分析:  gen_tcp调用进程收到{empty_out_q, Port}消息奇怪行为分析

最后小图一张 Natalie Portman :

[Erlang 0097] TCP半开的几个小测试相关推荐

  1. 网络编程释疑之:TCP半开连接的处理

    熟悉基于TCP协议进行linux高性能.高并发服务端编程的朋友肯定应该知道每个文件描述符及其所占的资源对并发量的影响.在这种7*24甚至*365不间断运行的服务器上,一个描述符被浪费,两个被浪费... ...

  2. [windows] 半开连接数

    引子 至少在3年以前,包括迅雷在内的很多下载软件都提供了"修改(破解)操作系统'TCP半开连接'数量限制(简称"半开连接数")"的功能,但是有部分用户并没有正确 ...

  3. 破除对于XP半开连接数限制的误解

    转贴自very资源网:http://board.verycd.com/t463463.html 最近看到有些帖子说"XP SP2每秒只允许10个人连接你的电脑"之类的误导性言论,深 ...

  4. TCP-Z V2.6.2 Build 20090409 (半开连接数监控与破解)

    为什么80%的码农都做不了架构师?>>>    软件名称: TCP-Z  (TCP-Z Network Monitor) 操作系统: Windows XP/2003/Vista/20 ...

  5. 通过Erlang构建TCP服务器

    文章来源:公众号-智能化IT系统. 走进Erlang 试想一个场景,在一个炎热的夏天,一群员工进入了一个会议室准备开会,刚进会议室坐下,大家都满头大汗,需要等大家都擦完汗,才好开始会议. 会议室的中间 ...

  6. nmap全开扫描,半开扫描_nmap扫描的阶段

    nmap全开扫描,半开扫描 Hello readers, hope you all doing well. 各位读者好,希望大家一切都好. For security researchers and h ...

  7. 半开连接(half-open connection)

    半开(half-open)连接 开始一个TCP连接需要三次握手协议,关闭TCP连接需要四次挥手协议.一旦连接已经建立,即使双方没有发送任何数据,TCP也会假设连接是存活的,除非能证明连接已经关闭. T ...

  8. MathType怎么编辑半开半闭区间

    数学中的公式有很多,涉及到各种各样的样式,这些公式都会用到不同的符号,每一个符号用在不同数学问题的公式中,都会有其特定的意义,比如括号.括号这个符号在除了能够表示优先运算之外,还可以代表区间的意思,小 ...

  9. 申宝证券-个股涨跌对半开

    周五大盘低开震荡下跌0.18%,深市则有创业板指上涨0.22%.化工.有色.传媒娱乐等板块涨幅居前,券商.石油.建材.煤炭和医药等领跌.热点题材中的汽配.盐湖提锂+锂电.元宇宙等领涨,光伏.磷+有机硅 ...

最新文章

  1. 皮一皮:死要面子啊...
  2. angularjs之browserTrigger
  3. 中国LED产业园区现状模式及投资策略分析报告2022-2028年版
  4. 能简单才不简单,仿Flickr.com:基于Flash+jQuery的一次性划选多文件并上传
  5. MySQL(二): 表的增删查改
  6. 线程Blocked--SynchronizedDemo
  7. explain for connection用法
  8. L3-001. 凑零钱-PAT团体程序设计天梯赛GPLT(01背包,动态规划)
  9. 数据中台公开课丨可以复用的中台架构建设经验与实践
  10. Oracle 更新多字段1
  11. 基于R语言GD包的Risk Map制作(批量生成)
  12. c语言程序如何防止盗用,如何用C语言程序盗取QQ密码
  13. 替代YY语音,自行搭建语音实时服务器
  14. 优麒麟桌面闪烁_UKUI 桌面环境登陆 Arch Linux!
  15. [个人资料整理]游戏类型总结
  16. 题解-hzy loves segment tree I
  17. sprintf() 格式化输出函数
  18. 如何简单的抓取网站数据
  19. logical_and(),logical_or(), logical_not(), logical_xor()用法详解
  20. Redis集群入门实践教程

热门文章

  1. 理解几个网络硬件(调制解调器、路由器、交换机)的基本作用
  2. Linux添加用户(user)到用户组(group)
  3. 求int在二进制存储时1的个数(C++)
  4. [转] 设计模式的六大设计原则
  5. ubuntu安装VMware Tools
  6. 计算机课组会议讲话,在计算机部教师会议上的讲话
  7. 树莓派+神经计算棒2实时人脸检测
  8. go channel 缓冲区最大限制_[Go区块链基础]go channel
  9. mysql序列号发生器
  10. MongoDB安装步骤