Upgrade to Pro — share decks privately, control downloads, hide ads and more …

TCP Socket Network Programming In Ruby

Bce999ccd03c7e20f952995aa57bc4cc?s=47 qhwa
November 17, 2015

TCP Socket Network Programming In Ruby

A brief introduction to TCP Socket related network programming in Ruby language.

Bce999ccd03c7e20f952995aa57bc4cc?s=128

qhwa

November 17, 2015
Tweet

Transcript

  1. TCP Socket Network Programming in Ruby

  2. @qhwa * husband * software engineer at Alibaba * creator

    of Gira
  3. TCP? Why should I care about?

  4. raw network programming is fun

  5. unix system functions are powerful

  6. for example

  7. 3VCZPO3BJMT 3VCZ &WFOU.BDIJOF

  8. 3VCZPO3BJMT 3VCZ &WFOU.BDIJOF

  9. 3VCZPO3BJMT 3VCZ &WFOU.BDIJOF

  10. 3VCZPO3BJMT 3VCZ &WFOU.BDIJOF

  11. 3VCZPO3BJMT 3VCZ &WFOU.BDIJOF

  12. 3VCZPO3BJMT 3VCZ &WFOU.BDIJOF

  13. some crystal b.t.w.

  14. Let’s play with TCP Socket!

  15. what will be covered today?

  16. * classical style * Interactive * Multiplexing * Event based

    * Make a Socks5 Proxy * Stateful Socks5 Proxy
  17. some background knowledges before going on (incase you didn’t know)

  18. Everything is file in UNIX read/write IO = read/ write

    through File Describer
  19. None
  20. 5$14PDLFU

  21. 5$14PDLFU #BTJD4PDLFU

  22. 5$14PDLFU #BTJD4PDLFU

  23. 5$14PDLFU #BTJD4PDLFU *0

  24. 5$14PDLFU #BTJD4PDLFU *0

  25. Socket Domain

  26. Socket Domain "'@-0$"-

  27. Socket Domain "'@-0$"- "'@*/&5

  28. Socket Domain "'@-0$"- "'@*/&5 "'@*/&5

  29. Socket Domain "'@-0$"- "'@*/&5 "'@*/&5 ʜ

  30. Socket Domain "'@-0$"- "'@*/&5 "'@*/&5 ʜ

  31. Socket Domain "'@-0$"- "'@*/&5 "'@*/&5 6/*9 ʜ

  32. Socket Domain "'@-0$"- "'@*/&5 "'@*/&5 6/*9 ʜ

  33. Socket Domain "'@-0$"- "'@*/&5 "'@*/&5 6/*9 *1W ʜ

  34. Socket Domain "'@-0$"- "'@*/&5 "'@*/&5 6/*9 *1W ʜ

  35. Socket Domain "'@-0$"- "'@*/&5 "'@*/&5 6/*9 *1W *1W ʜ

  36. Socket Type

  37. Socket Type 40$,@3"8

  38. Socket Type 40$,@3"8 40$,@%3".

  39. Socket Type 40$,@3"8 40$,@%3". 40$,@453&".

  40. Socket Type 40$,@3"8 40$,@%3". 40$,@453&". ʜ

  41. Socket Type 40$,@3"8 40$,@%3". 40$,@453&". ʜ

  42. Socket Type 40$,@3"8 40$,@%3". 40$,@453&". 5$1 ʜ

  43. Socket Protocol

  44. Socket Protocol *1@4$51

  45. Socket Protocol *1@4$51 *1@6%1

  46. Socket Protocol *1@4$51 *1@6%1 *1@5$1

  47. Socket Protocol *1@4$51 *1@6%1 *1@5$1 ʜ

  48. Socket Protocol *1@4$51 *1@6%1 *1@5$1 ʜ

  49. Socket Protocol *1@4$51 *1@6%1 *1@5$1 5$1 ʜ

  50. TCP Socket 40$,@453&". "'@*/&5"'@*/&5

  51. Let’s code

  52. 1. classical style

  53. None
  54. server

  55. bind server

  56. bind server

  57. bind listen server

  58. bind listen server

  59. bind listen accept server

  60. bind listen accept server client

  61. bind listen accept connect server client

  62. bind listen accept connect server client

  63. bind listen accept read connect server client

  64. bind listen accept read connect write server client

  65. bind listen accept read connect write server client

  66. bind listen accept read connect write server client

  67. bind listen accept read write connect write server client

  68. bind listen accept read write connect write server client

  69. bind listen accept read write connect write read server client

  70. bind listen accept read write connect write read close server

    client
  71. bind listen accept read write connect write read close server

    client
  72. bind listen accept read write close connect write read close

    server client
  73. None
  74. require 'socket'

  75. require 'socket'

  76. require 'socket' class Server

  77. require 'socket' class Server

  78. require 'socket' class Server def start(bind: '0.0.0.0', port: nil)

  79. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM)
  80. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM)
  81. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port
  82. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port sock.listen 0
  83. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port sock.listen 0
  84. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port sock.listen 0 client, client_addr = sock.accept
  85. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port sock.listen 0 client, client_addr = sock.accept client.puts "Hello there! %s" % Time.now
  86. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port sock.listen 0 client, client_addr = sock.accept client.puts "Hello there! %s" % Time.now client.close
  87. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port sock.listen 0 client, client_addr = sock.accept client.puts "Hello there! %s" % Time.now client.close sock.close
  88. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port sock.listen 0 client, client_addr = sock.accept client.puts "Hello there! %s" % Time.now client.close sock.close end
  89. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port sock.listen 0 client, client_addr = sock.accept client.puts "Hello there! %s" % Time.now client.close sock.close end
  90. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port sock.listen 0 client, client_addr = sock.accept client.puts "Hello there! %s" % Time.now client.close sock.close end end
  91. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port sock.listen 0 client, client_addr = sock.accept client.puts "Hello there! %s" % Time.now client.close sock.close end end
  92. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port sock.listen 0 client, client_addr = sock.accept client.puts "Hello there! %s" % Time.now client.close sock.close end end Server.new.start(port: 23333, bind: '127.0.0.1')
  93. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) sock

    = Socket.new(:INET, :STREAM) sock.bind Addrinfo.tcp bind, port sock.listen 0 client, client_addr = sock.accept client.puts "Hello there! %s" % Time.now client.close sock.close end end Server.new.start(port: 23333, bind: '127.0.0.1')
  94. ruby’s sugar

  95. None
  96. require 'socket'

  97. require 'socket' class Server

  98. require 'socket' class Server

  99. require 'socket' class Server def start(bind: '0.0.0.0', port: nil)

  100. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind,

    port) do |sock, remote|
  101. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind,

    port) do |sock, remote| sock.puts "Hello there! %s" % Time.now
  102. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind,

    port) do |sock, remote| sock.puts "Hello there! %s" % Time.now sock.close
  103. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind,

    port) do |sock, remote| sock.puts "Hello there! %s" % Time.now sock.close end
  104. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind,

    port) do |sock, remote| sock.puts "Hello there! %s" % Time.now sock.close end end
  105. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind,

    port) do |sock, remote| sock.puts "Hello there! %s" % Time.now sock.close end end
  106. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind,

    port) do |sock, remote| sock.puts "Hello there! %s" % Time.now sock.close end end end
  107. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind,

    port) do |sock, remote| sock.puts "Hello there! %s" % Time.now sock.close end end end
  108. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind,

    port) do |sock, remote| sock.puts "Hello there! %s" % Time.now sock.close end end end Server.new.start(port: 23333, bind: '127.0.0.1')
  109. require 'socket' class Server def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind,

    port) do |sock, remote| sock.puts "Hello there! %s" % Time.now sock.close end end end Server.new.start(port: 23333, bind: '127.0.0.1')
  110. 2. interactive

  111. ... def start(bind: '0.0.0.0', port: nil)

  112. ... def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock,

    client_addr|
  113. ... def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock,

    client_addr| log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] }
  114. ... def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock,

    client_addr| log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] }
  115. ... def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock,

    client_addr| log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!"
  116. ... def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock,

    client_addr| log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!"
  117. ... def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock,

    client_addr| log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!" loop do
  118. ... def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock,

    client_addr| log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!" loop do input = sock.gets.chomp
  119. ... def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock,

    client_addr| log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!" loop do input = sock.gets.chomp if input == "q"
  120. ... def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock,

    client_addr| log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!" loop do input = sock.gets.chomp if input == "q" sock.close
  121. ... def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock,

    client_addr| log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!" loop do input = sock.gets.chomp if input == "q" sock.close break
  122. ... def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock,

    client_addr| log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!" loop do input = sock.gets.chomp if input == "q" sock.close break end
  123. ... def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock,

    client_addr| log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!" loop do input = sock.gets.chomp if input == "q" sock.close break end sock.puts input.reverse
  124. 3. multiplexing

  125. def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock, client_addr|

    sock.puts "Welcome buddy!" loop do input = sock.gets.chomp if input == "q" sock.close else sock.puts input.reverse end end end end
  126. def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock, client_addr|

    sock.puts "Welcome buddy!" loop do input = sock.gets.chomp if input == "q" sock.close else sock.puts input.reverse end end end end Thread.new do end
  127. def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock, client_addr|

    sock.puts "Welcome buddy!" loop do input = sock.gets.chomp if input == "q" sock.close else sock.puts input.reverse end end end end Thread.new do end
  128. def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock, client_addr|

    log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!" loop do input = sock.gets.chomp if input == 'q' sock.close break else sock.puts input.reverse end end end end
  129. def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock, client_addr|

    log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!" loop do input = sock.gets.chomp if input == 'q' sock.close break else sock.puts input.reverse end end end end if fork else sock.close end
  130. def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock, client_addr|

    log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!" loop do input = sock.gets.chomp if input == 'q' sock.close break else sock.puts input.reverse end end end end if fork else sock.close end
  131. def start(bind: '0.0.0.0', port: nil) Socket.tcp_server_loop(bind, port) do |sock, client_addr|

    log { "client connected: %s:%d" % [client_addr.ip_address, client_addr.ip_port] } sock.puts "Welcome buddy!" loop do input = sock.gets.chomp if input == 'q' sock.close break else sock.puts input.reverse end end end end if fork else sock.close end
  132. None
  133. socket

  134. socket client

  135. socket client

  136. socket client

  137. socket socket client

  138. socket socket client

  139. socket socket client

  140. 3. EventMachine

  141. None
  142. require 'eventmachine'

  143. require 'eventmachine'

  144. require 'eventmachine' class Server

  145. require 'eventmachine' class Server def start(bind: '0.0.0.0', port: nil)

  146. require 'eventmachine' class Server def start(bind: '0.0.0.0', port: nil) EM.run

    { EM.start_server bind, port, Handler }
  147. None
  148. module Handler

  149. module Handler

  150. module Handler def receive_data data

  151. module Handler def receive_data data data.chomp!

  152. module Handler def receive_data data data.chomp! if data == "q"

  153. module Handler def receive_data data data.chomp! if data == "q"

    close_connection
  154. module Handler def receive_data data data.chomp! if data == "q"

    close_connection else
  155. module Handler def receive_data data data.chomp! if data == "q"

    close_connection else send_data data.reverse
  156. module Handler def receive_data data data.chomp! if data == "q"

    close_connection else send_data data.reverse send_data "\n"
  157. 4. EM SOCKS5 proxy server IUUQTHJUIVCDPNRIXBSVCZOFUXPSL QSPHSBNNJOHCMPCNBTUFSTFSWFS @FWFOUNBDIJOF@TPDLT@TFSWFSSC

  158. 5. EM SOCKS5 version 2 IUUQTHJUIVCDPNRIXBSVCZOFUXPSL QSPHSBNNJOHCMPCNBTUFSTFSWFS @TUSPOHFS@FWFOUNBDIJOF@TPDLT@TFSW FSSC

  159. 6. stateful SOCK5 proxy server

  160. module StatefulHandler include Socks5Handler def connect ip, _ = client_addr

    # to allow: redis-cli set allowed:127.0.0.1 1 # to disallow: redis-cli del allowed:127.0.0.1 EM.defer -> { Redis.new.get "allowed:#{ip}" }, -> (allowed) { allowed ? super : close_connection } end end
  161. TCP Programming models

  162. block IO start end non-block IO start end check check

    check check check signal driven IO notify end async IO start notify XBJUGPS EBUB DPQZEBUB GSPN LFSOFMUP VTFSTQBDF
  163. conclusions

  164. TCP Socket is easy, right?

  165. Thank you!