gen_tcp详解

该模块 提供一组基于tcp/ip协议 socket 网络通信方法。

gen_tcp:connect/3 gen_tcp:connect/4####

连接一个 TCP 端口

用法:
connect(Address, Port, Options, Timeout) -> {ok, Socket} | {error, Reason}
用给出的端口 Port 和 IP 地址 Address 连接到一个服务器上的 TCP 端口上。参数 Address 即可以是一个主机名,也可以是一个 IP 地址。

参数 Timeout 指定一个以毫秒为单位的超时值,默认值是 infinity。

{Rand, _RandSeed} = random:uniform_s(9999, erlang:now()),
Port = 40000 + Rand,
gen_tcp:connect("localhost", Port, [{active, false}, {packet, 0}], 5000).

Options选项:

gen_tcp:listen/2####

开启一个监听某个端口的套接字

用法:

listen(Port, Options) -> {ok, ListenSocket} | {error, Reason}

在本地开启一个监听某个端口的套接字(socket)。开启成功的话,会返回一个套接字标识符 Socket,其一般会传递给 get_tcp:accept/1 或 get_tcp:accept/2 调用。

如果参数 Port 为 0,那么底层操作系统将赋值一个可用的端口号,可以使用 inet:port/1 来获取一个 socket 监听的端口。

参数 Options 的一些常用选项:

{active, true}:套接字设置为主动模式。所有套接字接收到的消息都作为 Erlang 消息转发到拥有这个套接字进程上。当开启一个套接字时,默认是主动模式。
{active, false}:设置套接字为被动模式。套接字收到的消息被缓存起来,进程必须通过调用函数 gen_tcp:recv/2 或 gen_tcp:recv/3 来读取这些消息。
{active, once}:将设置套接字为主动模式,但是一旦收到第一条消息,就将其设置为被动模式,并使用 gen_tcp:recv/2 或 gen_tcp:recv/3 函数来读取后续消息。
{keepalive, true}:当没有转移数据时,确保所连接的套接字发送保持活跃(keepalive)的消息。因为关闭套接字消息可能会丢失,如果没有接收到保持活跃消息的响应,那么该选项可确保这个套接字能被关闭。默认情况下,该标签是关闭的。
{nodelay, true}:数据包直接发送到套接字,不过它多么小。在默认情况下,此选项处于关闭状态,并且与之相反,数据被聚集而以更大的数据块进行发送。
{packet_size, Size}:设置数据包允许的最大长度。如果数据包比 Size 还大,那么将认为这个数据包无效。
{packet, 0}:表示 Erlang 系统会把 TCP 数据原封不动地直接传送给应用程序
{reuseaddr, true}:允许本地重复使用端口号
{nodelay, true}:意味着很少的数据也会被马上被发送出去
{delay_send, true}:数据不是立即发送,而是存到发送队列里,等 socket 可写的时候再发送
{backlog, 1024}:缓冲区的长度
{exit_on_close, false}:设置为 flase,那么 socket 被关闭之后还能将缓冲区中的数据发送出去
{send_timeout, 15000}:设置一个时间去等待操作系统发送数据,如果底层在这个时间段后还没发出数据,那么就会返回 {error,timeout}

{Rand, _RandSeed} = random:uniform_s(9999, erlang:now()),  
Port = 40000 + Rand,  
gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}]).  

gen_tcp:accept/1 gen_tcp:accept/2
接受一个发送到监听套接字 ListenSocket 上的连接请求

用法:

accept(ListenSocket, TimeOut) -> {ok, Socket} | {error, Reason}

接受一个发送到监听套接字 ListenSocket 上的连接请求。ListenSocket 必须是由函数 gen_tcp:listen/2 建立返回。

该函数会引起进程阻塞,直到有一个连接请求发送到监听的套接字。

如果连接已建立,则返回 {ok,Socket};或如果 ListenSocket 已经关闭,则返回{error,closed};或如果在指定的时间内连接没有建立,则返回{error,timeout};或如果 Erlang 虚拟机里可用的端口都被使用了,则返回 {error, system_limit};如果某些东西出错,也可能返回一个 POSIX 错误。一些有可能的错误请查看 inet 模块的相关说明。

使用 gen_tcp:send/2 向该函数返回的套接字 Socket 发送数据包。往端口发送的数据包会以下面格式的消息发送:
{tcp, Socket, Data}
如果在建立套接字 Socket 的时候选项列表中指定了 {active,false},这样就只能使用 gen_tcp:recv/2 或 gen_tcp:recv/3 来接收数据包了。

{Rand, _RandSeed} = random:uniform_s(9999, erlang:now()),
Port = 40000 + Rand,
case gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}]) of
    {ok, ListenSocket} ->
        case gen_tcp:accept(ListenSocket) of
            {ok, Socket} ->
                Socket;
            {error, SocketAcceptFail} ->
                SocketAcceptFail
        end;
    _ ->
        socket_listen_fail
end.

gen_tcp:recv/3####

从一个被动模式的套接字接受一个数据包

用法:
recv(Socket, Length, Timeout) -> {ok, Packet} | {error, Reason}
这个函数是从一个被动模式的套接字接受一个数据包。如果返回一个 {error, closed} 的返回值,那表明 Socket 已经关闭。

当 Socket 是 raw 模式下,参数 Length 才有意义的,并且 Length 表示接收字节的大小。如果 Length = 0,所有有效的字节数据都会被接收。如果 Length > 0,则只会接收 Length 长度的字节,或发生错误;当另一端 Socket 关闭时,接收的数据长度可能会小于 Length。

选项 Timeout 是一个以毫秒为单位的超时值,默认值是 infinity。

{Rand, _RandSeed} = random:uniform_s(9999, erlang:now()),
Port = 40000 + Rand,
case gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}]) of
    {ok, ListenSocket} ->
        case gen_tcp:accept(ListenSocket) of
            {ok, Socket} ->
                gen_tcp:recv(Socket, 0, 5000);
            {error, SocketAcceptFail} ->
                SocketAcceptFail
        end;
    _ ->
        socket_listen_fail
end.

gen_tcp:send/2####

在一个套接字 Socket 发送一个数据包
用法:

send(Socket, Packet) -> ok | {error, Reason}

在一个套接字 Socket 发送一个数据包。

{Rand, _RandSeed} = random:uniform_s(9999, erlang:now()),
Port = 40000 + Rand,
case gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}]) of
    {ok, ListenSocket} ->
        case gen_tcp:accept(ListenSocket, 1500) of
            {ok, Socket} ->
                gen_tcp:send(Socket, "test!");
            {error, SocketAcceptFail} ->
                SocketAcceptFail
        end;
    _ ->
        socket_listen_fail
end.

gen_tcp:shutdown/2####

半关闭一个套接字

用法:
shutdown(Socket, How) -> ok | {error, Reason}
内部实现:

-spec shutdown(Socket, How) -> ok | {error, Reason} when
      Socket :: socket(),
      How :: read | write | read_write,
      Reason :: inet:posix().
 
shutdown(S, How) when is_port(S) ->
    case inet_db:lookup_socket(S) of
    {ok, Mod} ->
        Mod:shutdown(S, How);
    Error ->
        Error
    end.

以某种方式半关闭一个套接字。

如果参数 How 为 write 的形式,则套接字 socket 会关闭数据写入,读取仍可以正常执行。参数 How 为 read,则反之。

要实现套接字半打开, 那么套接字要设置 {exit_on_close, false} 这个参数。

{Rand, _RandSeed} = random:uniform_s(9999, erlang:now()),
Port = 40000 + Rand,
case gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}]) of
    {ok, ListenSocket} ->
        case gen_tcp:accept(ListenSocket, 1500) of
            {ok, Socket} ->
                inet:setopts(Socket, [{exit_on_close, false}]),
                gen_tcp:shutdown(Socket, write);
            {error, SocketAcceptFail} ->
                SocketAcceptFail
        end;
    _ ->
        socket_listen_fail
end.

gen_tcp:controlling_process/2####

改变一个套接字的控制进程

用法:
gen_tcp:controlling_process(Socket, Pid) -> ok | {error, Reason}
为 Socket 分配一个新的控制进程 Pid。控制进程就是接收发自套接字消息数据的进程。如果被当前控制进程以外的其他任何进程调用,则会返回 {error, not_owner} 的错误。

{Rand, _RandSeed} = random:uniform_s(9999, erlang:now()),
Port = 40000 + Rand,
case gen_tcp:listen(Port, [binary, {packet, 0}, {active, false}]) of
    {ok, Socket} ->
        gen_tcp:controlling_process(Socket, self());
    _ ->
        socket_listen_fail
end.

gen_tcp:close/1####

关闭一个 TCP 套接字
用法:

  gen_tcp:close(Socket) -> ok  

关闭一个 TCP 套接字。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,904评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,581评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,527评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,463评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,546评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,572评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,582评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,330评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,776评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,087评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,257评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,923评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,571评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,192评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,436评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,145评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • 1、TCP状态linux查看tcp的状态命令:1)、netstat -nat 查看TCP各个状态的数量2)、lso...
    北辰青阅读 9,423评论 0 11
  • 参考:http://www.2cto.com/net/201611/569006.html TCP HTTP UD...
    F麦子阅读 2,946评论 0 14
  • 好规划预见未来生活,富思维创造美好人生。 非常有幸能参加赛美老师的理财训练营,通过第一课的学习,我就感受到了学习的...
    江阴晓峰阅读 428评论 0 1
  • 01 昨天,参加一个公号的征集活动,翻看小茗同学的旧照,看到几张他小时候“看书”的照片,再看看他成长到现在的种种表...
    迅图阅读 908评论 0 2
  • 有偿问答,即知识变现,有别于免费的知识分享,被提问者的专业背书是首要的问题,值乎借助知乎平台构建起的大V形象,自然...
    NlrlN阅读 293评论 0 1