概述

  TCP/IP套接字接口

描述

  gen_tcp模块提供了使用TCP / IP协议与套接字进行通信的功能。

  以下代码片段提供了一个客户端连接到端口5678的服务器的简单示例,传输一个二进制文件并关闭连接:

client() ->

SomeHostInNet = "localhost", % to make it runnable on one machine

{ok, Sock} = gen_tcp:connect(SomeHostInNet, 5678, [binary, {packet, 0}]),

ok = gen_tcp:send(Sock, "Some Data"),

ok = gen_tcp:close(Sock).

  在另一端,服务器正在侦听端口5678,接受连接并接收二进制文件:

server() ->

{ok, LSock} = gen_tcp:listen(5678, [binary, {packet, 0},

{active, false}]),

{ok, Sock} = gen_tcp:accept(LSock),

{ok, Bin} = do_recv(Sock, []),

ok = gen_tcp:close(Sock),

Bin.

do_recv(Sock, Bs) ->

case gen_tcp:recv(Sock, 0) of

{ok, B} ->

do_recv(Sock, [Bs, B]);

{error, closed} ->

{ok, list_to_binary(Bs)}

end.

  有关更多示例,请参阅示例部分。

数据类型

option() = {active, true | false | once}
         | {buffer, integer() >= 0}
         | {delay_send, boolean()}
         | {deliver, port | term}
         | {dontroute, boolean()}
         | {exit_on_close, boolean()}
         | {header, integer() >= 0}
         | {high_msgq_watermark, integer() >= 1}
         | {high_watermark, integer() >= 0}
         | {keepalive, boolean()}
         | {linger, {boolean(), integer() >= 0}}
         | {low_msgq_watermark, integer() >= 1}
         | {low_watermark, integer() >= 0}
         | {mode, list | binary}
         | list
         | binary
         | {nodelay, boolean()}
         | {packet,
            0 |
            1 |
            2 |
            4 |
            raw |
            sunrm |
            asn1 |
            cdr |
            fcgi |
            line |
            tpkt |
            http |
            httph |
            http_bin |
            httph_bin}
         | {packet_size, integer() >= 0}
         | {priority, integer() >= 0}
         | {raw,
            Protocol :: integer() >= 0,
            OptionNum :: integer() >= 0,
            ValueBin :: binary()}
         | {recbuf, integer() >= 0}
   | {reuseaddr, boolean()}
         | {send_timeout, integer() >= 0 | infinity}
         | {send_timeout_close, boolean()}
         | {sndbuf, integer() >= 0}
         | {tos, integer() >= 0}
         | {ipv6_v6only, boolean()}

option_name() = active
              | buffer
              | delay_send
              | deliver
              | dontroute
              | exit_on_close
              | header
              | high_msgq_watermark
              | high_watermark
              | keepalive
              | linger
              | low_msgq_watermark
              | low_watermark
              | mode
              | nodelay
              | packet
              | packet_size
              | priority
              | {raw,
                 Protocol :: integer() >= 0,
                 OptionNum :: integer() >= 0,
                 ValueSpec :: (ValueSize :: integer() >= 0)
                            | (ValueBin :: binary())}
              | recbuf
              | reuseaddr
              | send_timeout
              | send_timeout_close
              | sndbuf
              | tos
              | ipv6_v6only

connect_option() = {ip, inet:ip_address()}
                 | {fd, Fd :: integer() >= 0}
                 | {ifaddr, inet:ip_address()}
                 | inet:address_family()
                 | {port, inet:port_number()}
                 | {tcp_module, module()}
                 | option()

listen_option() = {ip, inet:ip_address()}
                | {fd, Fd :: integer() >= 0}
                | {ifaddr, inet:ip_address()}
                | inet:address_family()
                | {port, inet:port_number()}
                | {backlog, B :: integer() >= 0}
                | {tcp_module, module()}
                | option()

socket()

  由accept/ 1,2和connect/ 3,4返回。

导出

connect(Address, Port, Options) -> {ok, Socket} | {error, Reason}
connect(Address, Port, Options, Timeout) -> {ok, Socket} | {error, Reason}

  Types:

    Address = inet:ip_address() | inet:hostname()

    Port = inet:port_number()

    Options = [connect_option()]

    Timeout = timeout()

    Socket = socket()

    Reason = inet:posix()

  连接到IP地址为Address的主机上的TCP端口Port上的服务器。 Address参数可以是主机名或IP地址。

  {ip, ip_address()}

  如果主机有多个网络接口,则此选项指定要使用哪一个。

  {ifaddr, ip_address()}

  与{ip, ip_address()}相同。 如果主机有多个网络接口,则此选项指定要使用哪一个。

  {fd, integer() >= 0}

  如果某个套接字在不使用gen_tcp的情况下以某种方式连接,请使用此选项为其传递文件描述符。

  inet

  设置IPv4的套接字。

  inet6

  设置IPv6的套接字。

  {port, Port}

  指定要使用的本地端口号。

  {tcp_module, module()}

  覆盖使用哪个回调模块。 默认为IPv4的inet_tcp和IPv6的inet6_tcp。

  Opt

  参见 inet:setopts/2.

  可以使用send / 2将数据包发送到返回的套接字Socket。 从对等方发送的数据包将作为消息发送:

  {tcp, Socket, Data}

  如果套接字已关闭,则会传递以下消息:

  {tcp_closed, Socket}

  如果套接字上发生错误,则传递以下消息:

  {tcp_error, Socket, Reason}

  除非在套接字的选项列表中指定{active,false},在这种情况下,通过调用recv/ 2来检索数据包。

  可选的Timeout参数指定以毫秒为单位的超时。 默认值是无穷大。

注意:

  给予连接的选项的默认值可能受内核配置参数inet_default_connect_options的影响。 有关详细信息,请参阅inet(3)。

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

  Types:

    Port = inet:port_number()

    Options = [listen_option()]

    ListenSocket = socket()

    Reason = system_limit | inet:posix()

  设置套接字以侦听本地主机上的端口Port。

  如果Port== 0,则底层操作系统会分配一个可用端口号,请使用inet:port/1来检索它。

  可用的选项是:

  list

  接收到的数据包作为列表提供。

  binary

  接收到的数据包以二进制形式提供。

  {backlog, B}

  B是>= 0的整数。backlog值默认为5。backlog值定义待处理连接队列可能增长到的最大长度。

  {ip, ip_address()}

  如果主机有多个网络接口,则此选项指定要监听哪个接口。

  {port, Port}

  指定要使用的本地端口号。

  {fd, Fd}

  如果某个套接字在不使用gen_tcp的情况下以某种方式连接,请使用此选项为其传递文件描述符。

  {ifaddr, ip_address()}

  与{ip,ip_address()}相同。 如果主机有多个网络接口,则此选项指定要使用哪一个。

  inet

  设置IPv4的套接字。

  inet6

  设置IPv6的套接字。

  {tcp_module, module()}

  覆盖使用哪个回调模块。 默认为IPv4的inet_tcp和IPv6的inet6_tcp。

  Opt

  参见 inet:setopts/2

  返回的套接字ListenSocket只能用于accept/1,2的调用。

注意:

  监听选项的默认值可能受内核配置参数inet_default_listen_options的影响。有关详细信息,请参阅inet(3)。

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

  Types:

    ListenSocket = socket()

    listen/2返回。

    Timeout = timeout()

    Socket = socket()

    Reason = closed | timeout | system_limit | inet:posix()

  在侦听套接字上接受传入的连接请求。套接字必须是从listen / 2返回的套接字。 超时以ms为单位指定超时值,默认为无穷大。

  如果连接已建立,则返回{ok,Socket};如果ListenSocket已关闭,则返回{error,closed};如果在指定的时间内未建立连接,则返回{error,timeout};如果所有可用端口都处于连接状态,则返回{error,system_limit} 。 如果出现其他问题,也可能返回一个POSIX错误值,请参阅inet(3)了解可能的错误值。

  可以使用send/2将数据包发送到返回的套接字Socket。从对等方发送的数据包将作为消息发送:

  {tcp, Socket, Data}

  除非在侦听套接字的选项列表中指定了{active,false},在这种情况下,通过调用recv/2来检索数据包。

注意:

  值得注意的是,接受调用不必从套接字所有者进程发出。 使用仿真器5.5.3及更高版本,可以从不同进程发出多个同时接受调用,这允许接收器进程池处理传入连接。

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

  Types:

    Socket = socket()

    Packet = iodata()

    Reason = closed | inet:posix()

  在套接字上发送数据包。

  发送调用没有超时选项,如果需要超时,可以使用send_timeout套接字选项。请参阅示例部分。

recv(Socket, Length) -> {ok, Packet} | {error, Reason}
recv(Socket, Length, Timeout) -> {ok, Packet} | {error, Reason}

  Types:

    Socket = socket()

    Length = integer() >= 0

    Timeout = timeout()

    Packet = string() | binary() | HttpPacket

    Reason = closed | inet:posix()

    HttpPacket = term()

  请参阅erlang中的HttpPacket说明:decode_packet/3。.

  该函数以被动模式从套接字接收数据包。关闭的套接字由返回值{error,closed}表示。

  Length参数仅在套接字处于原始模式时才有意义,并且表示要读取的字节数。 如果Length = 0,则返回所有可用的字节。 如果长度> 0,则返回确切的长度字节或错误; 当套接字从另一端关闭时可能丢弃少于Length数据的字节数据。

  可选的Timeout参数指定以毫秒为单位的超时。默认值是无穷大。

controlling_process(Socket, Pid) -> ok | {error, Reason}

  Types:

    Socket = socket()

    Pid = pid()

    Reason = closed | not_owner | inet:posix()

  为Socket分配一个新的控制进程Pid。 控制过程是从套接字接收消息的过程。 如果被当前控制进程以外的任何其他进程调用,则返回{error,not_owner}。

close(Socket) -> ok

  Types:

    Socket = socket()

  关闭TCP套接字。

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

  Types:

    Socket = socket()

    How = read | write | read_write

    Reason = inet:posix()

  立即关闭一个或两个方向的套接字。

  How==write意味着关闭写入套接字,从它读取仍然是可能的。

  为了能够处理对端在写入端执行关闭操作,{exit_on_close,false}选项很有用。

例子

  以下示例通过将服务器实现为在单个侦听套接字上进行接受的多个工作进程来说明{active,once}选项和多个接受的用法。 start/ 2函数使用工作进程的数量以及端口号监听即将到来的连接。 如果LPort指定为0,则使用临时端口号,为什么start函数返回分配的实际端口号:

start(Num,LPort) ->

case gen_tcp:listen(LPort,[{active, false},{packet,2}]) of

{ok, ListenSock} ->

start_servers(Num,ListenSock),

{ok, Port} = inet:port(ListenSock),

Port;

{error,Reason} ->

{error,Reason}

end.

start_servers(0,_) ->

ok;

start_servers(Num,LS) ->

spawn(?MODULE,server,[LS]),

start_servers(Num-1,LS).

server(LS) ->

case gen_tcp:accept(LS) of

{ok,S} ->

loop(S),

server(LS);

Other ->

io:format("accept returned ~w - goodbye!~n",[Other]),

ok

end.

loop(S) ->

inet:setopts(S,[{active,once}]),

receive

{tcp,S,Data} ->

Answer = process(Data), % Not implemented in this example

gen_tcp:send(S,Answer),

loop(S);

{tcp_closed,S} ->

io:format("Socket ~w closed [~w]~n",[S,self()]),

ok

end.

  一个简单的客户端可能是这样的:

client(PortNo,Message) ->

{ok,Sock} = gen_tcp:connect("localhost",PortNo,[{active,false},{packet,2}]),

gen_tcp:send(Sock,Message),

A = gen_tcp:recv(Sock,0),

gen_tcp:close(Sock),

A.

  发送调用不接受超时选项这一事实是因为发送超时是通过套接字选项send_timeout处理的。没有接收器的发送操作的行为在很大程度上由底层TCP堆栈以及网络基础结构定义。 如果想编写处理挂起的接收器的代码,最终可能会导致发送者挂起发送调用,则可以编写如下代码。

考虑一个从客户端进程接收数据的进程,该进程将被转发到网络上的服务器。该进程已通过TCP / IP连接到服务器,并且不会对其发送的每条消息进行确认,但必须依赖发送超时选项来检测另一端是否无响应。连接时我们可以使用send_timeout选项:

...

{ok,Sock} = gen_tcp:connect(HostAddress, Port,[{active,false},{send_timeout, 5000},{packet,2}]),

 loop(Sock), % See below

...

在处理请求的循环中,我们现在可以检测发送超时:

loop(Sock) ->

receive

{Client, send_data, Binary} ->

case gen_tcp:send(Sock,[Binary]) of

{error, timeout} ->

io:format("Send timeout, closing!~n",[]),

handle_send_timeout(), % Not implemented here

Client ! {self(),{error_sending, timeout}},

%% Usually, it's a good idea to give up in case of a

%% send timeout, as you never know how much actually

%% reached the server, maybe only a packet header?!

gen_tcp:close(Sock);

{error, OtherSendError} ->

io:format("Some other error on socket (~p), closing",[OtherSendError]),

Client ! {self(),{error_sending, OtherSendError}},

gen_tcp:close(Sock);

ok ->

Client ! {self(), data_sent},

loop(Sock)

end

end.

  通常,只需检测接收超时就足够了,因为大多数协议都包含来自服务器的某种确认,但如果协议是严格意义上的一种方法,那么send_timeout选项就派上用场了!

Erlang模块gen_tcp翻译的更多相关文章

  1. Erlang模块erl翻译

    命令:     erl 概述:     Erlang模拟器 描述:     erl程序启动一个Erlang运行时系统.准确的信息是依赖于系统的(举例,erl是否是脚本或程序,其它程序调用).     ...

  2. Erlang模块file翻译

    模块摘要     文件接口模块   描述     模块file提供了文件系统的接口.     在具有线程支持的操作系统上,可以让文件操作以其自己的线程执行,从而允许其他Erlang进程与文件操作并行地 ...

  3. Erlang模块ets翻译

    概要: 内置的存储 描述: 这个模块是Erlang内置存储BIFs的接口.这些提供了在Erlang运行时系统中存储大量数据的能力,并且能够对数据进行持续的访问时间.(在ordered_set的情况下, ...

  4. Erlang模块inet翻译

    模块 inet 模块概述 访问TCP / IP协议. 描述 此模块提供对TCP/IP协议的访问. 另请参阅<ERTS用户指南:Inet配置>,以获取有关如何配置用于IP通信的Erlang运 ...

  5. Erlang模块gen_server翻译

    gen_server 概要: 通用服务器行为描述: 行为模块实现服务器的客户端-服务器关系.一个通用的服务器进程使用这个模块将实现一组标准的接口功能,包括跟踪和错误报告功能.它也符合OTP进程监控树. ...

  6. Erlang模块gen_fsm翻译

    模块摘要     通用有限状态机行为.   描述     用于实现有限状态机的行为模块.使用该模块实现的通用有限状态机进程(gen_fsm)将具有一组标准的接口函数,并包括用于跟踪和错误报告的功能.它 ...

  7. Erlang模块supervisor翻译

    概要: 通用监督者行为   描述: 一个实现监督者的行为模块,一个监督被称为子进程的其它进程的进程.一个子进程可以是另一个监督者或工作者进程.工作者进程通常的实现使用gen_event,gen_fsm ...

  8. [Erlang25]Erlang in anger 翻译

    Erlang in anger     Erlang in anger 是写Learn some Erlang的帅小伙(照片真是帅死啦)写的,一共87页,可以随意下载(英文原版):http://www ...

  9. ns3 Tutorial 中的日志模块(翻译)

      转载地址:http://blog.sina.com.cn/s/blog_8ecca79b0101d7fe.html     1  日志模块的使用   在运行 first.cc 脚本时,我们已经简单 ...

随机推荐

  1. S2:log4j

    配置步骤 1.引入jar,放到lib中,jar包被项目管理 2.在src目录下copy了一个文件log4j.properties 3.使用Logger   String word="会员登记 ...

  2. ipad pro 为什么不行

    TalkingData公布的数据显示,iPad Pro在中国发行首月的销量仅为49 300台,而此前iPad Air 2发行首月后销量曾高达55.7万台.那么到底是什么原因,让这个被寄予厚望的iPad ...

  3. 详细分享TortoiseGit配置密钥的方法

    详细分享TortoiseGit配置密钥的方法 TortoiseGit 使用扩展名为ppk的密钥,而不是ssh-keygen生成的rsa密钥.使用命令ssh-keygen -C "邮箱地址&q ...

  4. Golang高效实践之array、slice、map

    前言 Golang的slice类型为连续同类型数据提供了一个方便并且高效的实现方式.slice的实现是基于array,slice和map一样是类似于指针语义,传递slice和map并不涉及底层数据结构 ...

  5. eclipse导入码云-GIT项目

    1.首先找到项目源码地址我随便找到一个git地址 :https://gitee.com/mingSoft/MCMS 2.打开eclipse空白处右键导入项目搜索git. 3.将第一步复制的git地址复 ...

  6. python基础知识 01

    一.计算机基础知识 计算机有硬件+操作系统+软件应用组成 cpu:人的大脑 内存:人的临时记忆 硬盘:人的永久记忆 操作系统 控制计算机硬件工作的流程 应用程序 安装在操作系统上的软件 二.Pytho ...

  7. cmd命令行带参启动程序

    cmd命令行带参启动程序 有一些程序不支持被直接启动,编写代码时,我们可以通过Process类来启动某个进程(某个软件),在不用代码调从而启动某个软件时,windows系统下,通常我们会用到cmd命令 ...

  8. 谈谈你对java平台的理解?

    问题:谈谈你对java平台的理解?java是解释执行,这句话对吗? 典型回答:java本身是一种面向对象的语言,具有很好的跨平台的能力,能够做到“write once ,run anywhere”.另 ...

  9. yaml文件解析详解

    前言 yaml文件是什么?yaml文件其实也是一种配置文件类型,相比较ini,conf配置文件来说,更加的简洁,操作也更加简单,同时可以存放不同类型的数据,不会改变原有数据类型,所有的数据类型在读取时 ...

  10. (转)2019年给Java编程初学者的建议(附学习大纲)

    本文链接:https://blog.csdn.net/javajlb/article/details/85920904 1. 引言这是一篇初学者干货,请耐心看完,希望对你有帮助 作为初学者的你,命中了 ...