Skip to content

Web Server

Socket

  1. Hierarchy:

    • Web app -> HTTP -> TCP/IP (Layer 4 -> transport layer)
    • Ruby socket(std-lib) -> standard socket API (Berkeley/POSIX Sockets)
    • Inheritance: TCPSocket -> IPSocket -> Socket -> BasicSocket -> IO
  2. Server (Listener)

    • Structure: Create -> Bind -> Listen -> Accept -> Close -> Listen

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      require 'socket'    # include socket in standard library
      
      # Step 1: Create
      sock_serv = Socket.new(
          domain,     # :INET => IPv4, :INET6 => IPv6, :UNIX => Unix Socket
          socket_type # :STREAM => TCP, DGRAM => UDP, RAW => ?
      )
      
      # Step 2: Bind
      addr = Socket.pack_sockaddr_in{
          port,   # int, (1025..48999)
          ip_addr # str, host machine
      }
      sock_serv.bind(addr)
      
      # Step 3: Listen (only for stream-oriented mode)
      sock_serv.listen(n)    # int, max num of conn, default 5, (1..Socket::SOMAXCONN)
      puts "Listening from host #{ip_addr} at port #{port} ..."
      
      # Step 4: Accept -> Close loop
      loop do
          conn = sock_serv.accept
          conn.close
      end
      

    • Syntax sugar

      • Combine Create -> Bind -> Listen

         1
         2
         3
         4
         5
         6
         7
         8
         9
        10
        11
        require 'socket'            # include socket in standard library
        
        sock_serv = TCPServer.new(  # TCPServer.listen(n) to chang conn, default 5
            ip_addr                 # str, host machine, default "127.0.0.1"
            port,                   # int, (1025..48999)
        )
        # server = Socket.tcp_server_sockets(port)    # same, default at localhost
        
        Socket.accept_loop(sock_serv) do |conn|
            conn.close              # next conn won't accepted until the block returns.
        end                         # Use Thread for multiple clients
        

      • √ Wrap all steps

        1
        2
        3
        4
        5
        require 'socket'
        
        Socket.tcp_server_sockets(host=nil, port) do |conn|
            conn.close
        end
        

  3. Client (Initate)

    • Structure: Create -> Connect -> Close

       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      require 'socket'    # include socket in standard library
      
      # Step 1: Create (same as server)
      sock_clnt = Socket.new(
          domain,     # :INET => IPv4, :INET6 => IPv6, :UNIX => Unix Socket
          socket_type # :STREAM => TCP, DGRAM => UDP, RAW => ?
      )
      
      # Step 2: Connect
      serv_addr = sock_clnt.pack_sockaddr_in{
          port,   # int, (1025..48999)
          ip_addr # str, host machine
      }
      sock_clnt.connect(serv_addr)
      

    • Syntax sugar: wrap all steps

      1
      2
      3
      4
      5
      6
      require 'socket'
      
      sock_clnt = TCPSocket.new(
          ip_addr                 # str, target server
          port,                   # int, (1025..48999)
      )
      

Web Server

  1. Socket connection -> file

    • "Read" socket

      1
      2
      3
      4
      5
      6
      require 'socket'
      
      Socket.tcp_server_loop(1234) do |conn|
          puts conn.gets
          conn.close
      end
      

    • "Write" socket

      1
      2
      3
      4
      require 'socket'
      
      sock_clnt = TCPSocket.new("localhost", 1234)
      sock_clnt.write(str)
      
  2. HTTP request Header

    1
    2
    3
    4
    5
    6
    GET /hello.htm HTTP/1.1
    User-Agent: Mozilla/4.0 (compatible; MSIE5.0; Windows NT)
    Host: www.tutorialpoint.com
    Accept-Language: en-us
    Accept-Encoding: gzip, deflate
    Connection: Keep-Alive
    
  3. HTTP Response Header

    1
    2
    3
    4
    5
    6
    GET /hello.htm HTTP/1.1
    User-Agent: Mozilla/4.0 (compatible; MSIE5.0; Windows NT)
    Host: www.tutorialpoint.com
    Accept-Language: en-us
    Accept-Encoding: gzip, deflate
    Connection: Keep-Alive
    

Web Client

  1. Net::HTTP library

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    require 'net/http'
    
    site - %{domainName.com}
    path = "/"
    
    response = Net::HTTP.get_response(site, path)
    puts "Code = #{response.code}"
    puts "Message = #{response.message}"
    
    response.each do |key, value|
        printf "%-15s = %-100s\n", key, value
    end
    
    p response.body[0, 500]
    
  1. open-uri library

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    require 'open-uri'
    
    site = %{domainName.com}
    
    open(site) do |f|
        puts "URI: #{f.base_uri}"
        puts "Content_type: #{f.content_type}"
        puts "Charset: #{f.charset}"
        puts "Encoding: #{f.content_encoding}"
        puts "Last modified: #{f.last_modified}"
        puts "Status: #{f.status.inspect}"
        puts
        puts "----- body -----"
        20.times {|n| puts "#{n}: #{f.gets}"}
    end