Permalink
Browse files

. a build

  • Loading branch information...
1 parent ef619a2 commit 2b0ead4318aab975939195b9339c0415cfa32dd4 @kschiess committed Apr 3, 2012
View
@@ -4,7 +4,7 @@
<link href="http://fonts.googleapis.com/css?family=Dosis" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/sh_whitengrey.css" media="screen" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/site.css" media="screen" rel="stylesheet" type="text/css" /><script src="/cod/javascripts/sh_main.min.js" type="text/javascript"></script><script src="/cod/javascripts/sh_ruby.min.js" type="text/javascript"></script><script src="/cod/javascripts/jquery-1.7.2.min.js" type="text/javascript"></script><title>cod - ipc, not beards</title>
</head>
<body onload="sh_highlightDocument();">
- <a href="/cod/tutorial/pipes.html">IO.pipes</a>-<a href="/cod/tutorial/pipes.html">TCP streams</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a><p>This is a work in progress&#8230;</p>
+ <a href="/cod/tutorial/pipes.html">IO.pipe</a> - <a href="/cod/tutorial/tcp.html">TCP/IP</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a><p>This is a work in progress&#8230;</p>
<p>Want to watch this happen? Here&#8217;s a list of things I&#8217;ve worked on recently
and what I changed:</p>
<h2>2012-04-02</h2>
@@ -4,7 +4,7 @@
<link href="http://fonts.googleapis.com/css?family=Dosis" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/sh_whitengrey.css" media="screen" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/site.css" media="screen" rel="stylesheet" type="text/css" /><script src="/cod/javascripts/sh_main.min.js" type="text/javascript"></script><script src="/cod/javascripts/sh_ruby.min.js" type="text/javascript"></script><script src="/cod/javascripts/jquery-1.7.2.min.js" type="text/javascript"></script><title>Pipes</title>
</head>
<body onload="sh_highlightDocument();">
- <a href="/cod/tutorial/pipes.html">IO.pipes</a>-<a href="/cod/tutorial/pipes.html">TCP streams</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a><p>channel often means a cod channel
+ <a href="/cod/tutorial/pipes.html">IO.pipe</a> - <a href="/cod/tutorial/tcp.html">TCP/IP</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a><p>channel often means a cod channel
cod is <em>cod</em>
examples don&#8217;t wait for children, but you should
very often, examples don&#8217;t close their channels, but you should</p><script type="text/javascript">(function() {
@@ -4,7 +4,7 @@
<link href="http://fonts.googleapis.com/css?family=Dosis" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/sh_whitengrey.css" media="screen" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/site.css" media="screen" rel="stylesheet" type="text/css" /><script src="/cod/javascripts/sh_main.min.js" type="text/javascript"></script><script src="/cod/javascripts/sh_ruby.min.js" type="text/javascript"></script><script src="/cod/javascripts/jquery-1.7.2.min.js" type="text/javascript"></script><title>Pipes</title>
</head>
<body onload="sh_highlightDocument();">
- <a href="/cod/tutorial/pipes.html">IO.pipes</a>-<a href="/cod/tutorial/pipes.html">TCP streams</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a>
+ <a href="/cod/tutorial/pipes.html">IO.pipe</a> - <a href="/cod/tutorial/tcp.html">TCP/IP</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a>
<div id="toc">
<img src="/cod/images/fish.png" />
<h1>Table of Contents</h1>
@@ -190,7 +190,7 @@
<p>Did you notice that a split pipe returns an array that also answers to
<code>#read</code> and <code>#write</code>? This is useful for when you cannot
come up with a name for both ends, as in the above example.</p>
-<p><img src="/images/fish.png" alt="" /></p>
+<p><img src="/cod/images/fish.png" alt="" /></p>
<p class="footnote" id="fn1"><a href="#fnr1"><sup>1</sup></a> man 2 pipe</p>
<p class="footnote" id="fn2"><a href="#fnr2"><sup>2</sup></a> @code_link(Cod::ConnectionLost)</p>
<p class="footnote" id="fn3"><a href="#fnr3"><sup>3</sup></a> Something that another library of mine could help you with:
@@ -4,7 +4,7 @@
<link href="http://fonts.googleapis.com/css?family=Dosis" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/sh_whitengrey.css" media="screen" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/site.css" media="screen" rel="stylesheet" type="text/css" /><script src="/cod/javascripts/sh_main.min.js" type="text/javascript"></script><script src="/cod/javascripts/sh_ruby.min.js" type="text/javascript"></script><script src="/cod/javascripts/jquery-1.7.2.min.js" type="text/javascript"></script><title>Pipes</title>
</head>
<body onload="sh_highlightDocument();">
- <a href="/cod/tutorial/pipes.html">IO.pipes</a>-<a href="/cod/tutorial/pipes.html">TCP streams</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a><h1>Selecting channels</h1><script type="text/javascript">(function() {
+ <a href="/cod/tutorial/pipes.html">IO.pipe</a> - <a href="/cod/tutorial/tcp.html">TCP/IP</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a><h1>Selecting channels</h1><script type="text/javascript">(function() {
var toc, ul;
toc = $('#toc');
@@ -4,7 +4,7 @@
<link href="http://fonts.googleapis.com/css?family=Dosis" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/sh_whitengrey.css" media="screen" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/site.css" media="screen" rel="stylesheet" type="text/css" /><script src="/cod/javascripts/sh_main.min.js" type="text/javascript"></script><script src="/cod/javascripts/sh_ruby.min.js" type="text/javascript"></script><script src="/cod/javascripts/jquery-1.7.2.min.js" type="text/javascript"></script><title>Pipes</title>
</head>
<body onload="sh_highlightDocument();">
- <a href="/cod/tutorial/pipes.html">IO.pipes</a>-<a href="/cod/tutorial/pipes.html">TCP streams</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a><h1>Serialisation</h1><script type="text/javascript">(function() {
+ <a href="/cod/tutorial/pipes.html">IO.pipe</a> - <a href="/cod/tutorial/tcp.html">TCP/IP</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a><h1>Serialisation</h1><script type="text/javascript">(function() {
var toc, ul;
toc = $('#toc');
@@ -4,7 +4,189 @@
<link href="http://fonts.googleapis.com/css?family=Dosis" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/sh_whitengrey.css" media="screen" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/site.css" media="screen" rel="stylesheet" type="text/css" /><script src="/cod/javascripts/sh_main.min.js" type="text/javascript"></script><script src="/cod/javascripts/sh_ruby.min.js" type="text/javascript"></script><script src="/cod/javascripts/jquery-1.7.2.min.js" type="text/javascript"></script><title>Pipes</title>
</head>
<body onload="sh_highlightDocument();">
- <a href="/cod/tutorial/pipes.html">IO.pipes</a>-<a href="/cod/tutorial/pipes.html">TCP streams</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a><h1><span class="caps">TCP</span> channels</h1><script type="text/javascript">(function() {
+ <a href="/cod/tutorial/pipes.html">IO.pipe</a> - <a href="/cod/tutorial/tcp.html">TCP/IP</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a>
+ <div id="toc">
+ <img src="/cod/images/fish.png" />
+ <h1>Table of Contents</h1>
+ </div><h1><span class="caps">TCP</span>/IP</h1>
+<p><span class="caps">TCP</span>/IP channels come in two varieties: client-side channels and server-side
+channels. Let me show you how to create both:</p>
+<pre class="sh_ruby"><code title="Basic tcp">
+ client = Cod.tcp('localhost:12345')
+ server = Cod.tcp_server('localhost:12345')
+
+ client.put 'tcp channels!'
+ server.get # =&gt; "tcp channels!"
+
+ client.close
+ server.close
+</code></pre>
+<p>To do simple communication across machines, this will be all you need. But that&#8217;s only where things start, not where they end. In the following sections,
+I&#8217;ll explain more about tcp clients and servers.</p>
+<h1>Client-side <span class="caps">TCP</span></h1>
+<p>The channel returned by <code>Cod.tcp</code> really acts in two phases:</p>
+<ul>
+ <li>Connection Phase: During this phase, the channel will buffer messages sent
+ through it. No server could be contacted, so nothing goes over the wire.</li>
+ <li>Established Phase: Once the connection could be established, all messages
+ that have been buffered are now sent. From now on, everything gets
+ transmitted immediately.</li>
+</ul>
+<p>This two-phase connect is the reason why <em>cod</em> programs can send stuff to a
+server that might not even be listening yet. This is very useful in practice.</p>
+<h2>Read Timeouts</h2>
+<p>If you want to force a connection, try to read from the client channel. It
+will block forever until data comes in. Look at this example, which tries to
+read from the channel until a timeout occurs:</p>
+<pre class="sh_ruby"><code title="Timeout">
+ channel = Cod.tcp('localhost:12345')
+
+ require 'timeout'
+ begin
+ value = timeout(0.1){ channel.get }
+ rescue Timeout::Error
+ end
+</code></pre>
+<p>Since there is normally no server on localhost:12345, the code will just block
+and wait, trying to make a connection. After 0.1 seconds, the timeout
+occurs and we abort processing.</p>
+<p>We have chosen not to handle timeouts in <em>cod</em> at all. A connection that did
+not deliver the data in time will often need to be reset; the data might still
+come later, and the client might not be in a condition to handle it. Use
+<code>timeout.rb</code>, it is your friend.</p>
+<h2>Connection lost</h2>
+<p>When the server terminates the connection to our client, we&#8217;ll eventually get
+a <code>Cod::ConnectionLost</code> error raised. This is pretty much the only
+error you have to expect and handle.</p>
+<pre class="sh_ruby"><code>
+ # Read until the connection breaks.
+ begin
+ loop { client.get }
+ rescue Cod::ConnectionLost
+ end
+</code></pre>
+<h1>Server-side <span class="caps">TCP</span></h1>
+<p>Writing a server with cod involves a few more concerns and tricks than writing
+a client. We&#8217;ve tried to address all obvious needs. Let&#8217;s look at what the
+innermost interaction with cod looks like naively:</p>
+<pre class="sh_ruby"><code>
+ # Get request
+ channel.get
+ # Put answer
+ channel.put # XXX doesn't exist
+</code></pre>
+<p>But there is no <code>Channel#put</code> for tcp server channels! A tcp server
+can of course have more than one client. There would be no way to tell which
+client should receive the answer.</p>
+<p>The easy answer to solving this problem is of course to send the server the
+channel to answer to. Here&#8217;s a working example of this:<sup class="footnote" id="fnr1"><a href="#fn1">1</a></sup></p>
+<pre class="sh_ruby"><code title="A more realistic server">
+ client do
+ channel = Cod.tcp('127.0.0.1:12345')
+ version = channel.interact [:ehlo, channel]
+ version # =&gt; [:version, 1]
+
+ other = channel.interact [:bark, channel]
+ other # =&gt; :unknown_command
+
+ # Tell the server to shut down.
+ channel.put [:shutdown, nil]
+ end
+
+ pid = server do
+ channel = Cod.tcp_server('127.0.0.1:12345')
+
+ loop do
+ msg, client = channel.get
+ case msg
+ when :ehlo
+ client.put [:version, 1]
+ when :shutdown
+ break
+ else
+ client.put :unknown_command
+ end
+ end
+ end
+
+ # Wait for the server to terminate
+ Process.wait pid
+</code></pre>
+<p>Of course, in your code, server and client would be on different machines.
+Otherwise what is the point. Right?</p>
+<h2>Identifying the Client</h2>
+<p>As you could see above, one method for the server to identify the clients
+that connect to it is for the clients to send the channel to answer to
+as part of the message.</p>
+<p>But sending the back-channel along has a few downsides:</p>
+<ul>
+ <li>Your code gets more complicated</li>
+ <li><span class="caps">TCP</span> has connection built in</li>
+</ul>
+<p>There is a better method to handle client connections in <em>cod</em>:</p>
+<pre class="sh_ruby"><code>
+ # Just the innermost server-side loop again
+ msg, back_channel = channel.get_ext
+ case msg
+ when ...
+ back_channel.put :answer
+ end
+</code></pre>
+<p>Using <code>#get_ext</code><sup class="footnote" id="fnr2"><a href="#fn2">2</a></sup> allows you to retrieve both the message that
+was sent and the back channel in one command. If you close that channel, you
+will terminate the clients connection.</p>
+<p>Here&#8217;s the revised example from above:</p>
+<pre class="sh_ruby"><code title="A more realistic server">
+ client do
+ channel = Cod.tcp('127.0.0.1:12345')
+ version = channel.interact :ehlo
+ version # =&gt; [:version, 1]
+
+ other = channel.interact :bark
+ other # =&gt; :unknown_command
+
+ # Tell the server to shut down.
+ channel.put :shutdown
+ end
+
+ pid = server do
+ channel = Cod.tcp_server('127.0.0.1:12345')
+
+ loop do
+ msg, client = channel.get_ext
+ case msg
+ when :ehlo
+ client.put [:version, 1]
+ when :shutdown
+ break
+ else
+ client.put :unknown_command
+ end
+ end
+ end
+
+ # Wait for the server to terminate
+ Process.wait pid
+</code></pre>
+<p>Note that the servers complexity remained the same, while the client got
+simpler. This is good, right?</p>
+<h2>Waiting for Data</h2>
+<h2>Dispatch Ideas</h2>
+<h3>The case Gem</h3>
+<h3>A clever Hash</h3>
+<h1>Competitive Comparison</h1>
+<p>Although we&#8217;re pretty sure that cod doesn&#8217;t perform badly, it probably will
+not quite match your evented/fiberthreaded/control-inversed server. Writing
+such a server is still hard. Comparing something you wrote in 5 minutes using
+<em>cod</em> to a program tuned for IO will not be a fair comparison.</p>
+<p>Evented IO is mostly overkill in day to day programming. Threading can be and
+often is actually harmful. What <em>cod</em> proposes is a saner and less convoluted
+way of expressing your needs. Make your choice.</p>
+<p><img src="/images/fish.png" alt="" /></p>
+<p class="footnote" id="fn1"><a href="#fnr1"><sup>1</sup></a> <code>#client</code> and <code>#server</code> are helper methods that
+ fork a client or a server process respectively. Treat them as synonymous to
+ <code>Kernel.fork</code>.</p>
+<p class="footnote" id="fn2"><a href="#fnr2"><sup>2</sup></a> @code_link(Cod::TcpServer#get_ext)</p><script type="text/javascript">(function() {
var toc, ul;
toc = $('#toc');
@@ -4,7 +4,7 @@
<link href="http://fonts.googleapis.com/css?family=Dosis" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/sh_whitengrey.css" media="screen" rel="stylesheet" type="text/css" /><link href="/cod/stylesheets/site.css" media="screen" rel="stylesheet" type="text/css" /><script src="/cod/javascripts/sh_main.min.js" type="text/javascript"></script><script src="/cod/javascripts/sh_ruby.min.js" type="text/javascript"></script><script src="/cod/javascripts/jquery-1.7.2.min.js" type="text/javascript"></script><title>Tricks and Gotchas to be aware of</title>
</head>
<body onload="sh_highlightDocument();">
- <a href="/cod/tutorial/pipes.html">IO.pipes</a>-<a href="/cod/tutorial/pipes.html">TCP streams</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a><h1>Tricks and Gotchas</h1>
+ <a href="/cod/tutorial/pipes.html">IO.pipe</a> - <a href="/cod/tutorial/tcp.html">TCP/IP</a>-<a href="/cod/tutorial/pipes.html">Beanstalkd tubes</a><h1>Tricks and Gotchas</h1>
<p>When you start using <em>cod</em> for your own projects, I assume you want to cross
over to the unixy, using-forks-instead-of-threads side of things. This is fine
with me, and one of the reasons I created cod.</p>

0 comments on commit 2b0ead4

Please sign in to comment.