<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Mundo Ruby &#187; TCP</title>
	<atom:link href="http://www.mundoruby.com.ar/tag/tcp/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.mundoruby.com.ar</link>
	<description>Ruby Artists, Hackers y otras yerbas ...</description>
	<lastBuildDate>Wed, 12 Aug 2009 23:02:13 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Bouncer básico en ruby</title>
		<link>http://www.mundoruby.com.ar/2009/05/06/bouncer-basico-en-ruby/</link>
		<comments>http://www.mundoruby.com.ar/2009/05/06/bouncer-basico-en-ruby/#comments</comments>
		<pubDate>Wed, 06 May 2009 13:40:58 +0000</pubDate>
		<dc:creator>FreedomCoder</dc:creator>
				<category><![CDATA[Open Source]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[TCP]]></category>

		<guid isPermaLink="false">http://www.mundoruby.com.ar/?p=84</guid>
		<description><![CDATA[&#8220;Estuve programando un bouncer, usando como base el load balancer que hice el año pasado. Un bouncer es un programa que poner un server TCP en un puerto y cada vez que recibe una conexión abre una conexión a otro lado y las &#8216;ata&#8217;, haciendo que el server al que se conecta le conteste al [...]]]></description>
			<content:encoded><![CDATA[<p>&#8220;Estuve programando un bouncer, usando como base el <a href="http://aurelianito.blogspot.com/2008/05/load-balancer-minimalista-en-ruby-parte.html">load balancer que hice el año pasado</a>. Un bouncer es un programa que poner un server TCP en un puerto y cada vez que recibe una conexión abre una conexión a otro lado y las &#8216;ata&#8217;, haciendo que el server al que se conecta le conteste al cliente que se conecta a él. <br />En mi caso lo programé para tener una salida controlada del entorno de máquinas virtuales que estoy armando para tener más ordenadas las cosas en el trabajo.<br />Por si les interesa, acá abajo pongo el código completo.<br />
<code><br />
#!/usr/bin/env ruby</p>
<p># == Synopsis<br />
#<br />
# redirect.rb: Redirects TCP connections to distant machines. Handles simultaneously many connections.<br />
#<br />
# == Usage<br />
#<br />
# ruby redirect.rb [OPTION]<br />
#<br />
# -h, --help:<br />
#   Show help<br />
#<br />
# --ip ip, -i ip:<br />
#   Accept connections from ip (default 127.0.0.1)<br />
#<br />
# --port port, -p port:<br />
#   Listen on port (default 12345)<br />
#<br />
# --target ip:port, -t ip:port<br />
#   Connect to ip:port (default 127.0.0.1:23456)<br />
#</p>
<p>require 'getoptlong'<br />
require 'rdoc/usage'<br />
require 'socket'</p>
<p>class Redirect<br />
 def initialize( source_ip, listening_port, target_ip, target_port )<br />
  @source_ip = source_ip<br />
  @target_ip = target_ip<br />
  @target_port = target_port</p>
<p>  @server_socket = TCPServer.new( "", listening_port )<br />
    @server_socket.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1 )</p>
<p>  @descriptors = [ @server_socket ]<br />
  @next_step = {}<br />
 end</p>
<p> def handle_new_connection<br />
  incoming = @server_socket.accept<br />
  if incoming.peeraddr[3] == @source_ip<br />
   begin<br />
    outgoing = TCPSocket.new( @target_ip, @target_port )</p>
<p>    @next_step[ incoming ] = outgoing<br />
    @next_step[ outgoing ] = incoming</p>
<p>    @descriptors += [ incoming, outgoing ]<br />
   rescue<br />
    silent_close( incoming )<br />
   end<br />
  else<br />
   silent_close( incoming )<br />
  end<br />
 end</p>
<p> def silent_close( sock )<br />
  begin<br />
   sock.close<br />
  rescue<br />
   #do nothing intentionally<br />
  end<br />
 end</p>
<p>  def propagate(sock)<br />
    next_sock = @next_step[sock]<br />
    next_sock.write(sock.read_nonblock(1000 * 1000))<br />
  end</p>
<p> def finish_connection(sock)<br />
  next_sock = @next_step[sock]<br />
  [ sock, next_sock ].each do<br />
   |s|<br />
   silent_close(s)<br />
   @descriptors.delete(s)<br />
   @next_step.delete(s)<br />
  end<br />
 end</p>
<p> def run<br />
  loop do<br />
   connections = select( @descriptors )<br />
   connections[0].each do<br />
    |sock|<br />
    if sock == @server_socket then<br />
     handle_new_connection<br />
    else<br />
     begin<br />
      sock.eof? ? finish_connection(sock) : propagate(sock)<br />
     rescue<br />
      finish_connection(sock)<br />
     end<br />
    end<br />
   end<br />
  end<br />
 end<br />
end</p>
<p>if $0 == __FILE__ then</p>
<p> opts = GetoptLong.new(<br />
   [ '--help', '-h', GetoptLong::NO_ARGUMENT ],<br />
   [ '--ip', '-i', GetoptLong::REQUIRED_ARGUMENT ],<br />
   [ '--port', '-p', GetoptLong::REQUIRED_ARGUMENT ],<br />
   [ '--target', '-t', GetoptLong::REQUIRED_ARGUMENT ]<br />
 )</p>
<p> ip = '127.0.0.1'<br />
 port = '12345'<br />
 target = '127.0.0.1:23456'</p>
<p> opts.each do<br />
  |opt, arg|<br />
  case opt<br />
  when '--help'<br />
   RDoc::usage<br />
   exit<br />
  when '--ip'<br />
   ip = arg<br />
  when '--port'<br />
   port = arg<br />
  when '--target'<br />
   target = arg<br />
  end<br />
 end</p>
<p> port = port.to_i<br />
 target = target.split(":")</p>
<p> trap("SIGINT") do<br />
   exit<br />
 end</p>
<p> Redirect.new(ip, port, target[0], target[1].to_i).run<br />
end<br />
</code></p>
<div class="blogger-post-footer"><img width='1' height='1' src='http://res1.blogblog.com/tracker/1437970354124720603-8701867554361547727?l=aurelianito.blogspot.com'/></div>
<p>&#8220;</p>
<p>(Via <a href="http://aurelianito.blogspot.com/">aurelianito</a>.) Original Link: <a href="http://aurelianito.blogspot.com/2009/05/bouncer-basico-en-ruby.html">Bouncer b&#225;sico en ruby</a></p>
<p><script type="text/javascript"><!--
google_ad_client = "pub-7949681675937032";
google_ad_slot = "0874687580";
google_ad_width = 468;
google_ad_height = 60;
//--></script>
<script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.mundoruby.com.ar/2009/05/06/bouncer-basico-en-ruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

