<?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> &#187; client/server</title>
	<atom:link href="http://googolflex.com/?feed=rss2&#038;cat=147" rel="self" type="application/rss+xml" />
	<link>http://googolflex.com</link>
	<description></description>
	<lastBuildDate>Fri, 06 Aug 2010 18:46:54 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Flex Socket Connections : Socket Policy File</title>
		<link>http://googolflex.com/?p=531</link>
		<comments>http://googolflex.com/?p=531#comments</comments>
		<pubDate>Tue, 09 Feb 2010 06:04:21 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Actionscript]]></category>
		<category><![CDATA[Application Servers]]></category>
		<category><![CDATA[Flex 3]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[client/server]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[socket policy file]]></category>
		<category><![CDATA[sockets]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=531</guid>
		<description><![CDATA[Starting with certain versions in the 9.0&#8217;s of Flash player, socket communication in Flex began adding additional security measures.  The one I am going to discuss in the post is the socket policy file.  In short, the socket policy file is an XML file that is served by default from port 843 and [...]]]></description>
			<content:encoded><![CDATA[<p>Starting with certain versions in the 9.0&#8217;s of Flash player, socket communication in Flex began adding additional security measures.  The one I am going to discuss in the post is the socket policy file.  In short, the socket policy file is an XML file that is served by default from port 843 and contains information regarding which ports on _this_ server that Flash may connect to.  Additionally it allows you to specify from which domains you wish to allow connections.</p>
<p></p>
<hr />
<strong><u>Loading the Policy File From Flex</u></strong></p>
<p>The policy file can be explicitly requested by making the call:</p>
<pre class="brush: as3;">
Security.loadPolicyFile(&quot;host.withpolicyfile.com:843&quot;);
</pre>
<p>Or you can trust it will implicitly make the request when you attempt a socket connection.  The policy is valid for a particular IP address over the life of the SWF.  A policy request consists of the following line, nothing more:</p>
<pre class="brush: xml;">&lt;policy-file-request/&gt;</pre>
<p>And the correct response is the policy file, followed by a null byte.  My example policy server file will not be so picky about it&#8217;s request, use it at your own risk.  Adobe has one that actually checks to see if the request was formatted correctly before sending the response.  Furthermore, rather than reading in an actual policy file, my example hard codes it into the policy server.</p>
<p></p>
<hr />
<strong><u>Policy File Format</u></strong></p>
<p>Here is a sample policy file, it is provided by Adobe.  You can make whatever changes you need to, as I did in mine:</p>
<pre class="brush: xml;">
&lt;?xml version=&quot;1.0&quot;?&gt;
&lt;!DOCTYPE cross-domain-policy SYSTEM &quot;/xml/dtds/cross-domain-policy.dtd&quot;&gt;

&lt;!-- Policy file for xmlsocket://socks.example.com --&gt;
&lt;cross-domain-policy&gt; 

   &lt;!-- This is a master socket policy file --&gt;
   &lt;!-- No other socket policies on the host will be permitted --&gt;
   &lt;site-control permitted-cross-domain-policies=&quot;master-only&quot;/&gt;

   &lt;!-- Instead of setting to-ports=&quot;*&quot;, administrator's can use ranges and commas --&gt;
   &lt;!-- This will allow access to ports 123, 456, 457 and 458 --&gt;
   &lt;!--allow-access-from domain=&quot;swf.example.com&quot; to-ports=&quot;123,456-458&quot; /--&gt;
   &lt;allow-access-from domain=&quot;*&quot; to-ports=&quot;80&quot; /&gt;
&lt;/cross-domain-policy&gt;
</pre>
<p></p>
<hr />
<strong><u>Policy File Server</u></strong></p>
<p>And here is the Perl code that runs the policy server.  You can see it is just a basic socket server.  Adobe&#8217;s version of this (which I based mine off) allows you to pass in the port as well as the path to the policy file.  This is a stripped down version of that server, with most of the essentials hard coded.</p>
<pre class="brush: perl;">
use Socket;

my $NULLBYTE = pack('c', 0);
my $port = 843;
my $content ='&lt;?xml version=&quot;1.0&quot;?&gt;'.&quot;\n&quot; .
'&lt;!DOCTYPE cross-domain-policy SYSTEM &quot;/xml/dtds/cross-domain-policy.dtd&quot;&gt;'.&quot;\n&quot; .
'&lt;cross-domain-policy&gt;' . &quot;\n&quot; .
   '&lt;site-control permitted-cross-domain-policies=&quot;master-only&quot;/&gt;'.&quot;\n&quot; .
   '&lt;allow-access-from domain=&quot;*&quot; to-ports=&quot;80&quot; /&gt;'.&quot;\n&quot; .
'&lt;/cross-domain-policy&gt;'.&quot;\n&quot;;

socket    (LISTENSOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp'))
          or die &quot;socket() error: $!&quot;;
setsockopt(LISTENSOCK, SOL_SOCKET, SO_REUSEADDR, pack('l', 1))
          or die &quot;setsockopt() error: $!&quot;;
bind      (LISTENSOCK, sockaddr_in($port, INADDR_ANY))
          or die &quot;bind() error: $!&quot;;
listen    (LISTENSOCK, SOMAXCONN)
          or die &quot;listen() error: $!&quot;;

while ( my $clientAddr = accept(CONNSOCK, LISTENSOCK)) {
    my ($clientPort, $clientIp)= sockaddr_in($clientAddr);
    my $clientIpStr = inet_ntoa($clientIp);

   # Consume the request
    local $/ = $NULLBYTE;
    my $request = &lt;CONNSOCK&gt;;
    chomp $request;

   # Send the policy file
    print CONNSOCK $content;
    print CONNSOCK $NULLBYTE;
    close CONNSOCK;
}
}
</pre>
<p></p>
<hr />
<strong><u>Opening A Port</u></strong></p>
<p>Remember to open port 843 (in Fedora Core) by adding the following line in /etc/sysconfig/iptables :</p>
<pre class="brush: bash;">-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 843 -j ACCEPT</pre>
<p>Then reload the iptables:</p>
<pre class="brush: bash;">/etc/init.d/iptables restart</pre>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=531</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple Flex Socket Client</title>
		<link>http://googolflex.com/?p=367</link>
		<comments>http://googolflex.com/?p=367#comments</comments>
		<pubDate>Tue, 09 Feb 2010 04:39:43 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Application Servers]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[Flex 3]]></category>
		<category><![CDATA[Web Services]]></category>
		<category><![CDATA[client/server]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[sockets]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=367</guid>
		<description><![CDATA[Client-server programming is one of my passions, and I enjoy doing it in almost any language.  Which makes it fitting that Flex (ActionScript) is one of my favorite languages to develop in, because it truly is a client-side technology which pretty much means it&#8217;s open to just about any type of backend server.  [...]]]></description>
			<content:encoded><![CDATA[<p>Client-server programming is one of my passions, and I enjoy doing it in almost any language.  Which makes it fitting that Flex (ActionScript) is one of my favorite languages to develop in, because it truly is a client-side technology which pretty much means it&#8217;s open to just about any type of backend server.  I suppose you could make that argument with just about any language depending on how it&#8217;s being used, but since Flex isn&#8217;t processed and returned to the browser as HTML, that makes it a little different in my opinion.</p>
<p>Even in Flex, most applications will connect to a backend server that&#8217;s running an HTTP service (which queries the database on behalf of Flex), but I&#8217;m even going to depart from that in this post.  I&#8217;m going to be demonstrating how to make socket calls to another service.  You could apply this to making HTTP requests on port 80, make requests directly to a MySQL server running on port 3306.  In this particular post, I will keep it simple by demonstrating how to make an HTTP request.</p>
<hr />
<strong><u>Declaring and initializing the Socket</u></strong></p>
<p>You declare socket like this:</p>
<pre class="brush: as3;">
import flash.net.Socket;

private var socket : Socket;
</pre>
<p>Inside an initialization method, we will add a listener for the CONNECT event, and the SOCKET_DATA event.  The CONNECT event alerts us when the connection has been made, and allows us to send our request.  The SOCKET_DATA event is triggered whenever there is data waiting to be read from the socket.</p>
<pre class="brush: as3;">
socket = new Socket();
socket.addEventListener( Event.CONNECT, onConnect);
socker.addEventListener( ProgressEvent.SOCKET_DATA, onSocketData);
</pre>
<hr />
<strong><u>Connecting and Sending Data</u></strong></p>
<p>At some point you will need to call connect on the socket, which accepts the URL of the server and the port it will be connecting to.  In the <code>onConnect()</code> method, you will write the request using one of the <code>writeXXX()</code> methods, and call <code>flush()</code> which actually sends the data over the wire.</p>
<pre class="brush: as3;">
socket.connect(txtUrl.text, 80);

private function onConnect(event : Event) : void {
   var requestString : String = getHttp_1_1Request();
   socket.writeUTFBytes(requestString);
   socket.flush();
}
</pre>
<hr />
<strong><u>Reading Data</u></strong></p>
<p>As not all socket data will be available at once, as in most client programs, you will want to read the data in a loop, using one of the <code>readXXX(</code>) methods.</p>
<pre class="brush: as3;">
private function onSocketData(event : ProgressEvent) : void {
   while (socket.bytesAvailable) {
      txtResponse.text += socket.readUTFBytes(socket.bytesAvailable);
   }
   socket.close();
}
</pre>
<p>In general you would be checking for the end of the response you&#8217;re expecting (based on protocol), to simplify things I simply close the socket after the while loop exits the first time.  If you leave the socket open for too long without reading data, I have noticed that I receive the following error, regardless of whether I have the correct policy file including cross-domain.xml:</p>
<p><code>Error #2044: Unhandled securityError:. filename.swf text=Error #2048: Security sandbox violation cannot load data from the.host.name</code></p>
<p>In this example, the raw output received from the socket request will be shown in the text box.  You can download the complete source to this example <a href="http://flexplanations.com/wp-content/uploads/2009/03/socketconnection.mxml">here </a>(where you may also view a screencast demo of this procedure).</p>
<p>Depending on what version of the Flash Player you&#8217;re running, this example may not run as-is if the server you are connecting to does not implement the policy-file (served from port 843.  I will be discussing this in an upcoming post where I delve into a little more advanced socket programming in Flex, including how and where to deploy a master policy file.</p>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=367</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Apache mod_proxy_balancer Self Registration : Part 3</title>
		<link>http://googolflex.com/?p=507</link>
		<comments>http://googolflex.com/?p=507#comments</comments>
		<pubDate>Thu, 04 Feb 2010 22:25:51 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Apache Web Server]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[Shell Scripting]]></category>
		<category><![CDATA[client/server]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[load balancing]]></category>
		<category><![CDATA[mod_proxy_balancer]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[self registration]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=507</guid>
		<description><![CDATA[I&#8217;ll start off by going over the basic high level architecture for my self registration procedure:
There is a register.php script residing on the load balancer, accessible via HTTP.
There is a deregister.php script residing on the load balancer, accessible via HTTP.
There is a register_with_lb.pl script residing on the web server, in /usr/local/bin/.
There is a deregister_with_lb.pl script [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ll start off by going over the basic high level architecture for my self registration procedure:</p>
<p>There is a register.php script residing on the load balancer, accessible via HTTP.<br />
There is a deregister.php script residing on the load balancer, accessible via HTTP.<br />
There is a register_with_lb.pl script residing on the web server, in /usr/local/bin/.<br />
There is a deregister_with_lb.pl script residing on the web server, in /usr/local/bin/.<br />
There is a MySQL database that stores the current configuration state, on it are two stored procedures register_lb and deregister_lb.</p>
<hr/>
<strong>register.php</strong></p>
<p>No changes were made to register.php as described in this <a href="http://googolflex.com/?p=494">post </a>, though I&#8217;m considering some alterations to increase its security.</p>
<hr/>
<strong>deregister.php</strong></p>
<p>The biggest difference between register.php and deregister.php (aside from their purpose) is where the insert/delete database code is called from and why.  When register.php is called by the web server, it will have already inserted information about itself into the database, including its hash.  I made the decision that I did not want the load balancer responsible for inserting servers into the database.  It would merely check that the requesting server inserted itself, and then regenerate the balancer_members.conf.</p>
<p>In the case of deregister.php I decided I wanted the server making the call to still be in the database so the script could verify the identity before removing it and regeneration the balancer_members.  And since the deregistration SQL is contained within a stored procedure, I needed to make some changes to the script (as compared to register.php) regarding the database.</p>
<p>Specifically, the standard mysql library cannot call stored procedures.  So I had to convert it to using mysqli, which is a similar, though more OO approach.  The portion of the code that regenerates the balancer_members.conf is similar enough that I won&#8217;t re-list it here, but I will show how to connect using mysqli, and how to call a stored procedure.</p>
<pre class="brush: php;">
$mysqli = new mysqli($dbhost, $dbuser, $dbpass, $dbname);
if (mysqli_connect_errno()) {
  printf(&quot;Connect failed: %s\n&quot;, mysqli_connect_error());
}

$query = &quot;SELECT count(*) as count FROM &quot; . $dbtable . &quot; WHERE ip='&quot; . $_SERVER['REMOTE_ADDR'] . &quot;';&quot;;
$result = $mysqli-&gt;query($query);
$row = $result-&gt;fetch_row();
echo $row[0];

if ($row[0] &gt;= 1) {
  $del_query = &quot;call deregister_lb('&quot; . $_SERVER['REMOTE_ADDR'] . &quot;');&quot;;
  $del_result = $mysqli-&gt;query($del_query);

  //&lt;code for regenerating the conf file removed here&gt;

  echo exec('echo &quot;' . $file . '&quot; &gt; /etc/httpd/conf.d/balancer_members.conf');
  echo exec(&quot;sudo /usr/local/bin/reload_httpd&quot;);
}
</pre>
<p>As you can see, I&#8217;m using the actual REMOTE_ADDR to determine the validity of the request.</p>
<hr/>
<strong>(de)register_lb.sql Stored Procedure</strong></p>
<p>Here is the code for the deregister_lb stored procedure:</p>
<pre class="brush: sql;">
DROP PROCEDURE IF EXISTS deregister_lb $$

CREATE PROCEDURE deregister_lb ( ip VARCHAR(100) )
  BEGIN
    DELETE FROM lb2_members
	WHERE ip=_ip;
  END $$
</pre>
<p>and also for the register_lb stored procedure:</p>
<pre class="brush: sql;">
DROP PROCEDURE IF EXISTS register_lb $$
CREATE PROCEDURE register_lb (
  _hostname VARCHAR(100),
  _ip VARCHAR(40),
  _loadfactor INT,
  _hash VARCHAR(100)
  )

  BEGIN
    DECLARE already_exists INT DEFAULT 0;
    SELECT count(*) INTO already_exists FROM lb2_members WHERE hash=_hash;

    IF already_exists=1 THEN
	  UPDATE lb2_members
	  SET hostname=_hostname, ip=_ip, loadfactor=_loadfactor
	  WHERE hash=_hash;
    ELSE
      INSERT INTO lb2_members (ip, hostname, loadfactor, hash)
	  VALUES (_ip, _hostname, _loadfactor, _hash);
    END IF;
  END $$
</pre>
<p>Note that I&#8217;ve omitted the code that changes the delimiter to $$ instead of a semicolon.</p>
<hr />
<strong>register_with_lb.pl</strong></p>
<p>This perl script uses perl DBI for accessing the database.  I had to get that installed on my web server since it wasn&#8217;t already.  Normally you can install perl packages using the cpan command.  In which case you would issue the following commands to install DBI and a MySQL driver for it:</p>
<pre class="brush: bash;">
cpan DBI
cpan DBD::mysql
</pre>
<p>If it&#8217;s the first time you&#8217;ve run cpan, you will need to go through some configuration.  It&#8217;s pretty much self explanatory, and I just accepted all of the defaults.  Everything installed correctly except for the MySQL driver, which I ended up having to install from source.  If I had executed the command:</p>
<pre class="brush: bash;">yum install mysql-devel.i386</pre>
<p>first, then my cpan install of DBD::mysql might have worked, but I didn&#8217;t realize that until installing from source.  In case you ever need to install a perl module from source, particularly the DBD::mysql driver, enter these commands (which I think is basically what cpan does):</p>
<pre class="brush: bash;">
yum install mysql-devel.i386 #(only requred in this particular instance)
wget http://www.cpan.org/modules/by-module/DBD/DBD-mysql-4.011.tar.gz
gzip -cd DBD-mysql-4.011.tar.gz | tar xf -
cd DBD-mysql-4.011 #(or whatever version you downloaded)
perl Makefile.PL
make
</pre>
<p>Here is how you connect to the database and call a stored procedure:</p>
<pre class="brush: perl;">
my $dsn = &quot;DBI:mysql:host=mysql.host;database=lb_register&quot;;
my $dbh = DBI-&gt;connect ($dsn, &quot;lbuser&quot;, &quot;lbpasswd&quot;)
  or die &quot;Cannot connect to MySQL server\n&quot;;

my $sql = &quot;call register_lb('&quot; . $localhost . &quot;', '&quot; . $localip . &quot;', &quot; . $loadfactor . &quot;, '&quot; .  $hash . &quot;')&quot;;
$dbh-&gt;do($sql);

$dbh-&gt;disconnect();
</pre>
<p>After that, register_with_lb.pl opens a socket to the load balancer and makes an HTTP request over the socket.  There are probably easier ways to do this, I just happened to have the socket code lying around and was glad to be able to reuse it.  Here&#8217;s the gist of it, in case you&#8217;re interested:</p>
<pre class="brush: perl;">
# Parse the URI.
my $url = URI-&gt;new(&quot;http://load.balancer.com/register/register.php?hash=&quot; . $hash);

# Parse these in from the command line
$host = $url-&gt;host;
$port = $url-&gt;port;
$resource = $url-&gt;path;
$query = $url-&gt;query;

# Initialize the socket
$socket = IO::Socket::INET-&gt;new ( Proto =&gt; &quot;tcp&quot;, PeerAddr =&gt; $host, PeerPort =&gt; $port,);
unless ($socket) { die &quot;Error connecting to $host&quot; }
$socket-&gt;autoflush(1);

# Format the request
my $request = &quot;GET &quot; . $resource . (($query)?&quot;?&quot; . $query : &quot;&quot;) . &quot; HTTP/1.1&quot; . $EOL . &quot;Host: &quot; . $host . $EOL . &quot;User-agent: register_script&quot; . $EOR;

# Use send() to make the request, and output the response.
# Not necessary in this example, but informational.
if ( $socket-&gt;send($request) ) {
  while ( &lt;$socket&gt; ) { print }
}

# Close the socket
close $socket;
</pre>
<p>The above code pretty much sums up deregister_from_lb.pl, since no database calls are made, a call is simply made to the deregister script.  The line you would change is as follows:</p>
<pre class="brush: perl;">my $url = URI-&gt;new(&quot;http://my.balancer.com/register/deregister.php&quot;);</pre>
<p>Then make the files executable, and copy them to be used by the startup script described in the previous <a href="http://googolflex.com/?p=499">post</a>:</p>
<pre class="brush: bash;">
chmod a+x register_with_lb.pl
chmod a+x deregister_with_lb.pl
cp register_with_lb.pl /usr/local/bin/
cp deregister_with_lb.pl /usr/local/bin
</pre>
<p>I don&#8217;t show it here, but right now my IP addresses are hard coded.  There are a number of ways you can find out your actual IP address from within perl, I&#8217;m just not doing that right now.</p>
<hr/>
<strong>Securing the register scripts</strong></p>
<p>As an additional security measure, I&#8217;ve restricted access to the /register/ location on the load balancer to the IP address range I expect my web servers to be from, like this:</p>
<pre class="brush: bash;">
&lt;Location /register&gt;
  Order Deny,Allow
  Deny from all
  Allow from 10.0.0.
&lt;/Location&gt;
</pre>
<p>And now you have a web server that can register automatically (if you&#8217;ve gone through the previous two posts as well) with a mod_proxy_balancer load balancer.</p>
<hr/>
<strong>Update</strong></p>
<p>I did some searching around to find a way to determine your IP address from inside the perl script.  This is a simple way if your server has a public IP address and reverse DNS set up correctly for that IP address:</p>
<pre class="brush: perl;">
use Socket;
use Sys::Hostname;
my $host = hostname();
my $addr = inet_ntoa(scalar(gethostbyname($host)) || 'localhost');
</pre>
<p>If your slave web servers are on a private network, the above command will return the loopback IP address (127.0.0.1) which isn&#8217;t useful for the load balancer (I wonder if it would start an infinite loop and crash the load balancer?).  I found a function that prints out the IP address by parsing it out from the results of the ifconfig command.</p>
<p>It seemed a little long to just rip off and copy verbatim.  So here&#8217;s a link to that code (which is what I&#8217;m using now) in case you&#8217;d like to use it.    <a href="http://ubuntuforums.org/showthread.php?t=273433">Perl script to get IP address</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=507</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apache mod_proxy_balancer Running Scripts at Startup/Shutdown : Part 2</title>
		<link>http://googolflex.com/?p=499</link>
		<comments>http://googolflex.com/?p=499#comments</comments>
		<pubDate>Thu, 04 Feb 2010 21:18:35 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Apache Web Server]]></category>
		<category><![CDATA[Shell Scripting]]></category>
		<category><![CDATA[client/server]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[load balancing]]></category>
		<category><![CDATA[mod_proxy_balancer]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[self registration]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=499</guid>
		<description><![CDATA[I think I have to break the self-registration into two posts, it took a lot longer than I expected last night.  This post deals with getting scripts to run at startup and shutdown on Linux.  I did this on Fedora, I imagine the process would be similar on Ubuntu, etc.
This is actually the [...]]]></description>
			<content:encoded><![CDATA[<p>I think I have to break the self-registration into two posts, it took a lot longer than I expected last night.  This post deals with getting scripts to run at startup and shutdown on Linux.  I did this on Fedora, I imagine the process would be similar on Ubuntu, etc.</p>
<p>This is actually the last thing I did, but I&#8217;m ordering it first because it&#8217;s a bit more general.  My goal was to have a script that I could call as follows to register with my load balancer manually:</p>
<pre class="brush: bash;">service lb_register start|stop|status|restart|reload|force-reload</pre>
<p>And then also to register this service to be called at startup and shutdown, to register and deregister with the load balancer respectively.</p>
<p>Let&#8217;s start with creating the script.  You can find tutorials for creating shell scripts just about anywhere on the web.  I found it easier to take an existing script from the /etc/init.d/ directory, clear it out and start from that shell.  Ironically the one that I chose was the startup script for Pound, another load balancer (a very good one, I might add).  It shouldn&#8217;t matter which one you use, since all we&#8217;re really after is the format.  The basic format is essentially the same for all of them: you have your function definitions at the top, and a case statement at the bottom.</p>
<p>The cases match the option parameters (start and stop are very common, as well as the others listed above in the callout).  And the case blocks generally call one or more of the functions.  I won&#8217;t list the case statement in this post as they are all very similar.  There are some important things to note in the function definitions, though.</p>
<p>Here is the definition for my start() function:</p>
<pre class="brush: bash;">
start() {
   echo -n $&amp;quot;Registering with the load balancer:&amp;quot;
   ./usr/local/bin/register_with_lb.pl
   touch /var/lock/subsys/lb_register
}
</pre>
<p>You can see that I call a perl script (which presumably registers with the load balancer).  Then I touch a file in the /var/lock/subsys/ directory.  <strong>This is very important if you want a script to automatically run at shutdown.  At shutdown the rc script will check for the presence of this file, if it is there it will call stop().  If it is not there, it assumes the service is stopped already and will not call stop() on the service.</strong></p>
<p>My stop function:</p>
<pre class="brush: bash;">
stop() {
   echo -n $&amp;quot;Deregistering with the load balancer: &amp;quot;
   ./usr/local/bin/deregister_with_lb.pl
   rm -f /var/lock/subsys/lb_register
}
</pre>
<p>This calls the deregister perl script, and then removes the lock file for good housekeeping.  There is one more thing about the script itself I want to mention before moving on to the registration.  There is a line in the comments of most of the scripts (if not all) in /etc/init.d/ that will look something like this:</p>
<pre class="brush: bash;"># chkconfig: - 85 10</pre>
<p>or</p>
<pre class="brush: bash;"># chkconfig: 2345 55 15</pre>
<p>These are directives to chkconfig (the command we&#8217;ll be getting to in a moment) on how to set this script up.  The &#8211; or the first grouping of numbers deal with the run levels.  It tells chkconfig what levels this script will be turned &#8220;on&#8221;.  It is assumed that it will be &#8220;off&#8221; in the omitted ones.</p>
<p>The second number is a startup priority, different scripts can have different startup priorities in case there are prerequisite dependencies.  In the two examples above, the script containing the bottom directive would run before the script containing the bottom one.  The last number is the shutdown priority, which is the same thing only during the shutdown process.</p>
<p>Once you have your script, you will need to run the chkconfig command.  To add your script to the startup process:</p>
<pre class="brush: bash;">chkconfig --add lb_register</pre>
<p>And should you need to remove it:</p>
<pre class="brush: bash;">chkconfig --del lb_register</pre>
<p>If you&#8217;ve done everything correctly, register_with_lb.pl will be called at startup, and deregister_with_lb.pl will be called at shutdown.  If it doesn&#8217;t, check that you&#8217;re touching the pid file, and that your scripts are executable.  You will also be able to make calls like this to deregister and register manually:</p>
<pre class="brush: bash;">
service lb_register start
service lb_register restart
service lb_register stop
</pre>
<p>I should mention a few sites that helped me out quite a bit:<br />
<a href="http://www.yolinux.com/TUTORIALS/LinuxTutorialInitProcess.html">Linux Init Processes</a><br />
<a href="http://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO.html">Introduction to BASH Programming</a><br />
<a href="http://gd.tuwien.ac.at/linuxcommand.org/html_text/new_script.html">An interesting script for creating new scripts</a></p>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=499</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apache mod_proxy_balancer Self Registration : Part 1</title>
		<link>http://googolflex.com/?p=494</link>
		<comments>http://googolflex.com/?p=494#comments</comments>
		<pubDate>Wed, 03 Feb 2010 20:39:12 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Amazon Web Services]]></category>
		<category><![CDATA[Apache Web Server]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[EC2]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[client/server]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[load balancing]]></category>
		<category><![CDATA[mod_proxy_balancer]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[self registration]]></category>
		<category><![CDATA[Shell Scripting]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=494</guid>
		<description><![CDATA[Load balancers are great, but they become even more powerful when servers have the ability to self-register when they come online, and deregister when they go offline.  This is especially true with services such as EC2, when the size of the server group might grow or shrink in response to need.  This is [...]]]></description>
			<content:encoded><![CDATA[<p>Load balancers are great, but they become even more powerful when servers have the ability to self-register when they come online, and deregister when they go offline.  This is especially true with services such as EC2, when the size of the server group might grow or shrink in response to need.  This is a tutorial describing my particular (partially insecure at the moment) solution for allowing self-registration with Apache&#8217;s mod_proxy_balancer.  Specifically this covers the load balancer side of the equation.  Tomorrow I hope to get a post out describing the server side.</p>
<p>Here is my flowchart for how self registration will work:<br />
1. Server comes online.<br />
2. A startup script will register itself with the MySQL database (including hostname, ip, loadfactor, and a hash that it will generate in some way).<br />
3. The server will then call a PHP script on the load balancer: &#8220;register/register.php&#8221;.<br />
4. The PHP script will verify that a server sent the request.<br />
5. The PHP script will query the database to get the current list of balancer members, and regenerate the balancer_members.conf file.<br />
6. The PHP script will then issue a command to reload Apache&#8217;s configuration files.</p>
<p>Deregistration, which my PHP script as presented doesn&#8217;t display, will work as follows:<br />
1. Server sends its hash to the PHP script, and shuts down.<br />
2. The PHP script will check the hash against the database.<br />
3. The PHP script will remove the server from the database.<br />
4. The PHP script will repeat steps 5 and 6 above.</p>
<p>First, set up the database and created a user with sufficient privileges.</p>
<pre class="brush: sql;">
CREATE DATABASE lb_register;
GRANT ALL ON lb_register.* TO 'lbuser'@'%' IDENTIFIED BY 'password';

CREATE TABLE lb2_members(
ip VARCHAR(20) NOT NULL PRIMARY KEY,
hostname VARCHAR(100) NOT NULL,
loadfactor INT NOT NULL DEFAULT 0,
hash VARCHAR(40) );
</pre>
<p>Second, create the PHP script.</p>
<pre class="brush: php;">
$dbhost = &quot;mysql.host.com&quot;;
$dbuser = &quot;lbuser&quot;;
$dbpass = &quot;password&quot;;
$dbname = &quot;lb_register&quot;;
$dbtable = &quot;lb2_members&quot;;

$conn = mysql_connect($dbhost, $dbuser, $dbpass) or die (mysql_error());
mysql_select_db($dbname);

$query = &quot;SELECT count(*) as count FROM &quot; . $dbtable . &quot; WHERE hash='&quot; . $_GET['hash'] . &quot;';&quot;;
$result = mysql_query($query);

$row = mysql_fetch_assoc(mysql_query($query));
if ($row['count'] &gt;= 1) {

  $file = &quot;&lt;Proxy balancer://mycluster&gt;&quot; . &quot;\n&quot;;
  $member_query = &quot;SELECT hostname, loadfactor FROM &quot; . $dbtable . &quot;;&quot;;
  $member_result = mysql_query($member_query);

  while ($row = mysql_fetch_array($member_result, MYSQL_BOTH)) {
    $file .= &quot;   BalancerMember http://&quot; . $row['hostname'] . &quot; &quot;;
    $file .= ($row['loadfactor'] &gt; 1) ? (&quot;loadfactor=&quot; . $row['loadfactor'] . &quot;\n&quot;) : &quot;\n&quot;;
  }
  $file .= &quot;&lt;/Proxy&gt;&quot;;

  exec('echo &quot;' . $file . '&quot; &gt; /etc/httpd/conf.d/balancer_members.conf');
  exec(&quot;sudo /usr/local/bin/reload_httpd&quot;);
}

mysql_close($conn);
</pre>
<p>You can tell a few things about the server configuration by looking at the script:<br />
1. User apache will need to be able to write to the &#8220;/etc/httpd/conf.d/balancer_members.conf&#8221; file.<br />
2. User apache will need to be able to execute the script &#8220;/usr/local/bin/reload_httpd&#8221;.<br />
3. User apache will need sudoer rights.<br />
4. This script was used for debugging, and not by a server that is actually registering&#8230; tyou can see that deregistration is not handled yet.</p>
<p>To grant write privileges to apache, I changed the owner of the balancer_members.conf to apache.</p>
<pre class="brush: bash;"> chown apache /etc/httpd/conf.d/balancer_members.conf</pre>
<p>This is probably the least secure aspect of my solution, as if the apache user were compromised, then any directives could be written to this file.  I&#8217;m not sure how big a threat this is, but it&#8217;s something that concerns me at least enough to think about this some more (and invite suggestions).</p>
<p>Next is to grant apache privileges to execute &#8220;/usr/local/bin/reload_httpd&#8221;.  We could accomplish this the same as we did above, but then it wouldn&#8217;t allow apache to execute what&#8217;s inside of the script, which is this:</p>
<pre class="brush: bash;">
#!/bin/bash
service httpd reload
</pre>
<p>unless we give execution rights to apache on service, which we don&#8217;t want.  What we also don&#8217;t want is for apache to be able to write to the file reload_httpd.  So what I ended up doing was, as you see in the script, to make root the owner of reload_httpd and remove write privileges for all (so apache couldn&#8217;t change it) and then add apache to the sudoers file, granting rights to execute this script without a password.</p>
<pre class="brush: bash;">visudo</pre>
<p>is the generally accepted way to edit the sudoers file.  And I added this line:</p>
<pre class="brush: bash;">apache ALL=(ALL) NOPASSWD: /usr/local/bin/reload_httpd</pre>
<p>I&#8217;m open to more secure ways of implementing this aspect as well, as I don&#8217;t consider myself a sudo configuration expert.  I think this gives apache rights to execute everything from anywhere if he knows the password; but he can also execute the /usr/local/bin/reload_httpd script without a password.</p>
<p>I also had to comment out the line:</p>
<pre class="brush: bash;">#Defaults   requiretty</pre>
<p>to allow sudo to function properly from a script not executed in a terminal.</p>
<p>Finally I had to disable proxying for the register script in my balancer.conf file:</p>
<pre class="brush: bash;">ProxyPass /register/ !</pre>
<p>And then your server is configured to dynamically update its list of balance members, you can check by going to the balancer-manager if you&#8217;ve got that enabled.  Next I will discuss how to handle the web server side of things.</p>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=494</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apache mod_proxy_balancer: No Protocol handler was valid</title>
		<link>http://googolflex.com/?p=492</link>
		<comments>http://googolflex.com/?p=492#comments</comments>
		<pubDate>Wed, 03 Feb 2010 04:09:36 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Apache Web Server]]></category>
		<category><![CDATA[Architecture]]></category>
		<category><![CDATA[HTTP Servers]]></category>
		<category><![CDATA[Scalability]]></category>
		<category><![CDATA[client/server]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[error message]]></category>
		<category><![CDATA[mod_proxy_balancer]]></category>
		<category><![CDATA[no protocol]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=492</guid>
		<description><![CDATA[Just this afternoon, one of my colleagues and I were discussing our feelings about the &#8220;semicolon-class&#8221; of bugs that developers will inevitably spin their wheels on from time to time.  I&#8217;ve had just such an experience the past two evenings with what started out as a simple recipe from the Apache Cookbook, entitled &#8220;Load [...]]]></description>
			<content:encoded><![CDATA[<p>Just this afternoon, one of my colleagues and I were discussing our feelings about the &#8220;semicolon-class&#8221; of bugs that developers will inevitably spin their wheels on from time to time.  I&#8217;ve had just such an experience the past two evenings with what started out as a simple recipe from the Apache Cookbook, entitled &#8220;Load Balancing with mod_proxy_balancer&#8221;.</p>
<p>The recipe itself is straightforward, taking up just over a page.  I was able to get a basic load balancer working within a few minutes by following the recipe, but for some reason I couldn&#8217;t get the balancer-manager site to load correctly.  The following directives should configure the balancer-manager:</p>
<pre class="brush: bash;">
&lt;Location /balancer-manager&gt;
  SetHandler balancer-manager
  Order Deny,Allow
  Allow from all
&lt;/Location&gt;
</pre>
<p>When I would start the server, however, I got an HTTP 500 error response, with this message in the log:</p>
<pre class="brush: bash;">
[Tue Feb 02 12:49:09 2010] [warn] proxy: No protocol handler was valid for the URL /balancer-manager. If you are using a DSO version of mod_proxy, make sure the proxy submodules are included in the configuration using LoadModule.
</pre>
<p>My searches on Google were fruitless: most people were able to solve the problem by ensuring these lines were added to their httpd.conf:</p>
<pre class="brush: bash;">
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
</pre>
<p>But they were already included in my conf file, so no dice.  Other people solved their problem by loading the mod_proxy_html.so, which doesn&#8217;t come on a standard install of Apache.  I ended up compiling it from source (learned a lot about compiling Apache shared modules) but that didn&#8217;t work for me either.</p>
<p>Eventually I realized that the only time my requests were being proxied to the BalancerMembers was when I was at the URL root, for example tacking on an &#8216;index.php&#8217; to the URL would generate the same error as trying to access &#8216;balancer-manager&#8217;.  And about that time I stumbled upon a user who was able to solve their problem by adding a few rewrite rules&#8230; which caused me to finally understand part of my problem.</p>
<p>The reason &#8216;balancer-manager&#8217; wasn&#8217;t loading correctly was because that request was being proxied to the BalancerMember, which didn&#8217;t have &#8216;balancer-manager&#8217; enabled (hence the &#8216;no protocol handler error&#8217;).  This still didn&#8217;t explain why &#8216;index.php&#8217; wasn&#8217;t working, either, since I knew index.php was on the BalancerMembers.</p>
<p>These discoveries quickly culminated into leading me to my solution, which was a missing trailing-slash in my ProxyPass directive.  That&#8217;s what was causing my &#8216;index.php&#8217; to not be proxied.  Once I realized the problem was in my ProxyPass&#8211; reading the documentation also taught me that there&#8217;s a way to keep certain requests from being proxied (which solved my &#8216;balancer-manager&#8217; issue).</p>
<p>So I present to you, my completed (and functional) balancer.conf.  And remember, <strong>the trailing slash at the end of the ProxyPass directive IS CRUCIAL!</strong></p>
<pre class="brush: bash;">
ProxyPass /balancer-manager !  # Prevents balancer-manager from being proxied.
ProxyPass / balancer://mycluster/
ProxyPassReverse / balancer://mycluster/

&lt;Proxy balancer://mycluster&gt;
  BalancerMember http://10.0.0.10 loadfactor=2
  BalancerMember http://10.0.0.11
  BalancerMember http://10.0.0.12
&lt;/Proxy&gt;

&lt;Location /balancer-manager&gt;
  SetHandler balancer-manager
  Order Allow,Deny
  Allow from all
&lt;/Location&gt;
</pre>
<p>I hope this saves someone some time when searching on the particular error message I got.  Now I&#8217;m off to figure out how to get my web servers to auto register with the balancer-manager.  I will blog about it when I figure it out.</p>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=492</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP Warning: mysql_connect(): Can&#8217;t connect to MySQL server on&#8230; (13)</title>
		<link>http://googolflex.com/?p=482</link>
		<comments>http://googolflex.com/?p=482#comments</comments>
		<pubDate>Tue, 02 Feb 2010 17:34:43 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Apache Web Server]]></category>
		<category><![CDATA[HTTP Servers]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[client/server]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[error message]]></category>
		<category><![CDATA[fedora]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[selinux]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=482</guid>
		<description><![CDATA[I created some barebones Fedora servers that I&#8217;m intending to create a load balanced cluster from using Apache&#8217;s mod_proxy_balancer.  My topology will eventually look like this:
load_balancer -> (ws1, ws2, ws3) -> mysql_server
As you can see, it&#8217;s nothing fancy.  To test the balancer, each web server has a PHP script that connects to the [...]]]></description>
			<content:encoded><![CDATA[<p>I created some barebones Fedora servers that I&#8217;m intending to create a load balanced cluster from using Apache&#8217;s mod_proxy_balancer.  My topology will eventually look like this:</p>
<p>load_balancer -> (ws1, ws2, ws3) -> mysql_server</p>
<p>As you can see, it&#8217;s nothing fancy.  To test the balancer, each web server has a PHP script that connects to the MySQL database and inserts its hostname and IP address.  Then I could run a simple query to determine whether the balancer was distributing the load according to my rules.</p>
<p>The PHP script was basic too:</p>
<pre class="brush: php;">
$dbhost = &quot;mysql.host.com&quot;;
$dbuser = &quot;testuser&quot;;
$dbpass = &quot;testpass&quot;;

$conn = mysql_connect($dbhost, $dbuser, $dbpass) or die (mysql_error());
$dbname = &quot;testdb&quot;;
mysql_select_db($dbname);

$query = &quot;INSERT INTO testtable(ip, host) VALUES('&quot; . $_SERVER[&quot;SERVER_ADDR&quot;] . &quot;', '&quot; . $_SERVER[&quot;SERVER_NAME&quot;] . &quot;');&quot;;

print $query;
mysql_query($query);
mysql_close($conn);
</pre>
<p>I&#8217;ve done this a thousand times, so you can imagine my frustration at getting this error message:</p>
<pre class="brush: bash;">[Mon Feb 01 16:22:21 2010] [error] [client 192.168.1.1] PHP Warning:  mysql_connect() [&lt;a href='function.mysql-connect'&gt;function.mysql-connect&lt;/a&gt;]: Can't connect to MySQL server on 'mysql.host.com' (13) in /var/www/html/index.php on line 7
</pre>
<p>I spent almost 2 hours looking for various solutions. I&#8217;ll list the most common ones in case you&#8217;re searching for a solution and mine doesn&#8217;t work for you:<br />
&#8211;Ensure that MySQL user permissions are configured correctly.<br />
&#8211;Ensure that MySQL is running on the server and on the correct port<br />
&#8211;Ensure that selinux is not blocking the MySQL port or the mysqld process</p>
<p>These three items can be tested by simply logging into MySQL from a remote host using the following command:</p>
<pre class="brush: bash;">mysql -u testuser -p -h mysql.host.com testdb</pre>
<p>If that gives you a MySQL prompt, you can rule out the above three causes.</p>
<p>Some of the less obvious suggestions, which didn&#8217;t solve my problem either were:<br />
&#8211;Ensure MySQL is using the correct path to the mysql.sock in my.ini<br />
&#8211;Ensure that the server wasn&#8217;t started with &#8211;skip-networking</p>
<p>Though I tried a number of configuration changes for both MySQL, the server MySQL was running on (including disabling selinux completely), and PHP, I failed to overlook that selinux was blocking Apache&#8217;s outgoing connections to the MySQL database.</p>
<p>So what finally solved my problem was disabling selinux completely on the server Apache was running on. I should have done this in the first place, as I normally do with my Linux desktop installations.</p>
<p>This can be accomplished by changing a line in /etc/selinux/config. Change the line that says:</p>
<pre class="brush: bash;">SELINUX=enforcing</pre>
<p>to</p>
<pre class="brush: bash;">SELINUX=disabled</pre>
<p>If you do some searching you can find out how to add an exception for Apache, after 2 hours I didn&#8217;t feel like fussing with those.</p>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=482</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Simple Client in C++</title>
		<link>http://googolflex.com/?p=322</link>
		<comments>http://googolflex.com/?p=322#comments</comments>
		<pubDate>Tue, 18 Aug 2009 16:15:16 +0000</pubDate>
		<dc:creator>jwd</dc:creator>
				<category><![CDATA[Architecture]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[client/server]]></category>
		<category><![CDATA[client server architecture]]></category>
		<category><![CDATA[sockets]]></category>

		<guid isPermaLink="false">http://googolflex.com/?p=322</guid>
		<description><![CDATA[Although a TCP client is fundamentally different from a TCP server, setting up the socket is very much the same.  For a server, we called these methods in this order:
socket()→bind()→listen()→accept(), followed by sequences of read() and write().
For a client we will call these methods in this order:
socket()→connect(), followed by sequences of write() and read() [...]]]></description>
			<content:encoded><![CDATA[<p>Although a TCP client is fundamentally different from a TCP server, setting up the socket is very much the same.  For a server, we called these methods in this order:</p>
<p><code>socket()</code>→<code>bind()</code>→<code>listen()</code>→<code>accept()</code>, followed by sequences of <code>read()</code> and <code>write()</code>.</p>
<p>For a client we will call these methods in this order:</p>
<p><code>socket()</code>→<code>connect()</code>, followed by sequences of <code>write()</code> and <code>read()</code> depending on what your server does.</p>
<p>To illustrate, I will create a simple HTTP client in C++, which has the following usage:</p>
<pre class="brush: bash;">client www.googolflex.com</pre>
<p>It will then make a connection on port 80 of the server specified at the command line, send an HTTP 1.1 request, and then dump the response to the console.</p>
<p>It uses the following variables:</p>
<pre class="brush: cpp;">
int sock;
struct sockaddr_in client;
int PORT = 80;
</pre>
<p>The first thing to do is initialize the socket structure, for this we need the IP address of the host.  You can use the <code>gethostbyname(char *)</code> function to do that, which passes back a <code>hostent</code> structure.  I have encapsulated the socket setup into a method, which shows how to extract the necessary values from the <code>hostent</code> struct, here:</p>
<pre class="brush: cpp;">
void setupSocket(char* hostname) {
	struct hostent * host = gethostbyname(hostname);

	if ( (host == NULL) || (host-&gt;h_addr == NULL) ) {
		cout &lt;&lt; &quot;Error retrieving DNS information.&quot; &lt;&lt; endl;
		exit(1);
	}

	bzero(&amp;client, sizeof(client));
	client.sin_family = AF_INET;
	client.sin_port = htons( PORT );
	memcpy(&amp;client.sin_addr, host-&gt;h_addr, host-&gt;h_length);

	sock = socket(AF_INET, SOCK_STREAM, 0);

	if (sock &lt; 0) {
		cout &lt;&lt; &quot;Error creating socket.&quot; &lt;&lt; endl;
		exit(1);
	}
}
</pre>
<p>If this method executes correctly, then we have a socket, and an address structure that we can use to call <code>connect()</code> with.  Here is my encapsulating method:</p>
<pre class="brush: cpp;">
void connectToHost(char* hostname) {
	if ( connect(sock, (struct sockaddr *)&amp;client, sizeof(client)) &lt; 0 ) {
		close(sock);
		cout &lt;&lt; &quot;Could not connect to &quot; &lt;&lt; hostname &lt;&lt; endl;
		exit(1);
	}
}
</pre>
<p>Finally, we can call <code>send()/write()</code> and <code>read()/recv()</code>.  This is where your protocol would be implemented, if you were to modify this for use with something other than simple HTTP requests.  Here my <code>sendRequest()</code> and <code>getResponse()</code> methods:</p>
<pre class="brush: cpp;">
void sendRequest(char* hostname) {
	string request = &quot;GET / HTTP/1.1\r\nHost: &quot;;
	request+= string(hostname);
	request += &quot;\r\n\r\n&quot;;

	if (send(sock, request.c_str(), request.length(), 0) != (int)request.length()) {
		cout &lt;&lt; &quot;Error sending request.&quot; &lt;&lt; endl;
		exit(1);
	}
}
</pre>
<pre class="brush: cpp;">
void getResponse() {
	char cur;
	while ( read(sock, &amp;cur, 1) &gt; 0 ) {
		cout &lt;&lt; cur;
	}
}
</pre>
<p>In <code>main()</code> I call these four methods in sequence, passing in the hostname parameter where needed.  And that&#8217;s it.  The full source is included at the end of the post.</p>
<p>Socket connections really aren&#8217;t that difficult once you&#8217;ve done it several times.  Next I will be demonstrating how to set up a simple client in Flex using a client.  Many scripting languages have abstracted away much of the difficulty surrounding socket connections (as we will see with Flex) leaving you to focus on implementing your protocol.</p>
<p>Download the source for <a href='http://googolflex.com/wp-content/uploads/2009/07/simpleclient.cpp'>simpleclient</a> here.  It can be compiled as follows:</p>
<pre class="brush: bash;">g++ -Wall -o client simpleclient.cpp</pre>
]]></content:encoded>
			<wfw:commentRss>http://googolflex.com/?feed=rss2&amp;p=322</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
