require "./ip_socket" # A Transmission Control Protocol (TCP/IP) socket. # # NOTE: To use `TCPSocket`, you must explicitly import it with `require "socket"` # # Usage example: # ``` # require "socket" # # client = TCPSocket.new("localhost", 1234) # client << "message\n" # response = client.gets # client.close # ``` class TCPSocket < IPSocket {% begin %} # Creates a new `TCPSocket`, waiting to be connected. def self.new(family : Family = Family::INET, {% if compare_versions(Crystal::VERSION, "1.5.0") >= 0 %} @[Deprecated("Use Socket.set_blocking instead.")] {% end %} blocking = nil) super(af: family, type: Type::STREAM, protocol: Protocol::TCP, blocking: blocking) end {% end %} {% begin %} # Creates a new TCP connection to a remote TCP server. # # You may limit the DNS resolution time with `dns_timeout` and limit the # connection time to the remote server with `connect_timeout`. Both values # must be in seconds (integers or floats). def initialize(host : String, port, dns_timeout = nil, connect_timeout = nil, {% if compare_versions(Crystal::VERSION, "1.5.0") >= 0 %} @[Deprecated("Use Socket.set_blocking instead.")] {% end %} blocking = nil) Addrinfo.tcp(host, port, timeout: dns_timeout) do |addrinfo| super(af: addrinfo.family, type: addrinfo.type, protocol: addrinfo.protocol, blocking: blocking) connect(addrinfo, timeout: connect_timeout) do |error| close error end end end {% end %} protected def initialize(family : Family, type : Type, protocol : Protocol = Protocol::IP) super family, type, protocol end # Internal constructor for `TCPServer#accept?`. # The *blocking* arg is purely informational. protected def initialize(*, handle, family, type, protocol, blocking) super(handle: handle, family: family, type: type, protocol: protocol, blocking: blocking) end {% begin %} # Creates an UNIXSocket from an existing system file descriptor or socket # handle. # # This adopts *fd* into the IO system that will reconfigure it as per the # event loop runtime requirements. # # NOTE: On Windows, the handle must have been created with # `WSA_FLAG_OVERLAPPED`. def initialize(*, fd : Handle, family : Family = Family::INET, {% if compare_versions(Crystal::VERSION, "1.5.0") >= 0 %} @[Deprecated("Use Socket.set_blocking instead.")] {% end %} blocking = nil) super fd, family, Type::STREAM, Protocol::TCP, blocking end {% end %} # Opens a TCP socket to a remote TCP server, yields it to the block, then # eventually closes the socket when the block returns. # # Returns the value of the block. def self.open(host : String, port, &) sock = new(host, port) begin yield sock ensure sock.close end end # Returns `true` if the Nagle algorithm is disabled. def tcp_nodelay? : Bool getsockopt_bool LibC::TCP_NODELAY, level: Protocol::TCP end # Disables the Nagle algorithm when set to `true`, otherwise enables it. def tcp_nodelay=(val : Bool) setsockopt_bool LibC::TCP_NODELAY, val, level: Protocol::TCP end # The amount of time in seconds the connection must be idle before sending keepalive probes. def tcp_keepalive_idle system_tcp_keepalive_idle end def tcp_keepalive_idle=(val : Int) self.system_tcp_keepalive_idle = val end # The amount of time in seconds between keepalive probes. def tcp_keepalive_interval system_tcp_keepalive_interval end def tcp_keepalive_interval=(val : Int) self.system_tcp_keepalive_interval = val val end # The number of probes sent, without response before dropping the connection. def tcp_keepalive_count system_tcp_keepalive_count end def tcp_keepalive_count=(val : Int) self.system_tcp_keepalive_count = val end end