Exceptions
To
IO
PickAxe
Companion
Notes
Peter
Komisar
v.1.2.1
Conestoga
College
reference:
Programming
Ruby
1.9,
The
Pragmatic Programmers Guide Thomas, Fowler
& Hunt
http://blog.nicksieger.com/articles/2006/09/06/rubys-exception-hierarchy
Sockets
programming in Ruby,
IBM
https://www6.software.ibm.com/developerworks/education/l-rubysocks/l-rubysocks-a4.pdf
Tutorials
Point,
http://www.tutorialspoint.com/ruby/ruby_input_output.htm
RailsTips,
http://railstips.org/blog/archives/2009/05/11/class-and-instance-methods-in-ruby/
Lee
Java Wordpress,
http://leejava.wordpress.com/2009/08/24/udp-client-and-server-in-ruby/
Tutorials
Pointhttp://www.tutorialspoint.com/ruby/ruby_socket_programming.htm
Ruby and Java were both released in
1995. The authors
of these languages must have both been reading
from the
same book with respect to exception handling. The
models
used are quite similar though they use different
keywords.
Ruby's model offers a few extra control options
compared
to that of Java.
Errors
Happen
Errors
happen and need to be managed. A typo that put
a letter into
a number, a File constructor that opens on a
non-existent file or
a 'divide by zero' are classic error
examples that need to be
dealt with.
In the early days, error return codes were
popularly used.
( i.e. HTTP 404 ) The Ruby interpreter is also an
example
of this approach.
Ruby
interpreter Normal Exit Code
Exit
code: 0
The Exception
Model: A Better Way
Packaging
error conditions in Exception class objects, that
carry information
about the error back to the user interface
provides a better way
to handle errors.
The Exception Class
Ruby,
as in Java, has a root Exception class that acts as a
root for a
large family of error conditions. The following code
lists the Exception classes available in Ruby. The output
has
been further formatted for added clarity.
Code Listing Ruby Exception Classes //
by Nick
Sieger
http://blog.nicksieger.com/articles/2006/09/06/rubys-exception-hierarchy
exceptions = []tree = {}ObjectSpace.each_object(Class) do |cls|next unless cls.ancestors.include? Exceptionnext if exceptions.include? clsnext if cls.superclass == SystemCallError # avoid dumping Errno'sexceptions << clscls.ancestors.delete_if {|e| [Object, Kernel].include? e }.reverse.inject(tree) {|memo,cls| memo[cls] ||= {}}endindent = 0tree_printer = Proc.new do |t|t.keys.sort { |c1,c2| c1.name <=> c2.name }.each do |k|space = (' ' * indent); space ||= ''puts space + k.to_sindent += 2; tree_printer.call t[k]; indent -= 2endendtree_printer.call treeOUTPUT// extra formatting addedBasicObject|_ Exception|_NoMemoryError|_ScriptError| |_LoadError| |_NotImplementedError| |_SyntaxError||_SecurityError||_SignalException| |_Interrupt||_StandardError| |_ArgumentError| |_EncodingError| | |_Encoding::CompatibilityError| | |_Encoding::ConverterNotFoundError| | |_Encoding::InvalidByteSequenceError| | |_Encoding::UndefinedConversionError| || |_FiberError| |_IOError| | |_EOFError| |_IndexError| | |_KeyError| | |_StopIteration| || |_LocalJumpError| |_Math::DomainError| |_NameError| | |_NoMethodError| || |_RangeError| | |_FloatDomainError| || |_RegexpError| |_RuntimeError| |_SystemCallError| |_ThreadError| |_TypeError| |_ZeroDivisionError||_SystemExit|_SystemStackError|_fatalChoose 'Built in' or 'Custom'The built in Exception classes are available for the Rubyprogrammer to use. The programmer can also extendStandardError or one of it's descendants to create customexceptions.A class that extends StandardError inherits the errorcatching mechanisms by default.The following code opens a URL connection on IBMand redirects the contents to a file under the C drive.
Example// adapted from Programming Ruby, 1.9.2, Thomas,Fowler & Huntrequire 'open-uri'web_page = open("http://www.ibm.com")output = File.open("c://ibm.html", "w")while line = web_page.getsoutput.puts lineendoutput.closeOUTPUT// see C drive
Look for ibm.html under C in a browser. It is probablymissing content but the idea is there.But What if A Problem Arises?Now had there been a download error it would be goodto allow the program to make a graceful exit.Here is the related text example with exception handlingin place. As in the text the key error handling words arehighlighted.Example// adapted from Programming Ruby, 1.9.2, Thomas,Fowler & Huntrequire 'open-uri'page = "podcasts"file_name = "#{page}.html"web_page = open("http://pragprog.com/#{page}")output = File.open(file_name, "w")beginwhile line = web_page.getsoutput.puts lineendoutput.closerescueExceptionSTDERR.puts "Failed to download #{page}: #{$!}"output.closeFile.delete(file_name)raiseendFollowing is the form of the exception handling blocks.In addition to the keywords shown in the above examplethere is a optional else clause that may be included.Exception Handling Blockbegin# protected coderescue# error handlingretry
# used to rerun block on a conditionelse# no error commentensure# always executes regardlessend
Begin Block Parts
begin - houses code that is being monitored
rescue -provides the response to raising an exception
else - executes if no error has been raised
ensure - always executed, good for freeing resources
end - end of begin block
It is hard to resist comparing to Java.Ruby & Java's Exception Handling Compared
|
Ruby Keywords |
Java Keywords |
|
begin |
try |
|
rescue |
catch |
|
else |
------ |
|
retry |
----- |
|
ensure |
finally |
Ruby uses the begin block to house code that mightthrow an exception, and within it, the rescue clause tosupply a response ifan exception occurs.The else clause acts as a 'no problem' reporter. The ensure clause is an 'always execute' section that runs whether an exception is thrown or not.The Global Variable $! Holds a Reference to Raised ExceptionWhen an exception is raised a reference to it is placed intothe global variable $!.A raise without parameters will re-raise the exceptionreferenced in $1. This technique facilitates passing onexceptions that have not been handled.To demonstrate this consider the classic 'divide by zero'error, caught in the following example.Divide by Zero Error Capture Examplebegin1 / 0# the old divide by zerorescueputs "It's a zero divide"print "What is $! holding? --> " , $!,"\n"elseputs "This isn't going to make the console! "ensureputs " Is there something that has to be done?"endOUTPUTIt's a zero divideWhat is $! holding? --> divided by 0Is there something that has to be done?In the above example the default Exception super'catch all' class is implicitly specified.Specifying Exception Types "With Multiple Rescue ClausesThe following example shows you can have multiplerescue blocks. In each of these rescue clauses aparticular exception is specified.The rescues aretested in turn and the first match is executed. Herethe second one is executed. If no match is found theexception is raised outside the block.Examplebegin1/0# the old divide by zerorescue TypeErrorputs "RESCUE 1"print "Exception Type --> " , $!,"\n"rescue ZeroDivisionErrorputs "RESCUE 2"print "Exception Type --> " , $!,"\n"endOUTPUTRESCUE 2Exception Type --> divided by 0The effect of the raise statement can be seen inthe output where the exit code changes from thenormal zero to having the exception forwarded tothe console from main.// described in text as 're-raising the exception in $!Effect of the Unparamaterized rescue Statementbegin1/0 # the old divide by zerorescue ZeroDivisionError# raiseendOUTPUT// without raiseExit code: 0OUTPUT// commenting the raise inexception.rb:2:in `/': divided by 0 (ZeroDivisionError)from exception.rb:2:in `<main>'>Exit code: 1Naming the Raised ExceptionThe following example shows a variable can beintroduced to provide a name tag for the exceptionthat is thrown.Examplebegin1/0 # the old divide by zerorescue ZeroDivisionError=>zeroDivputs zeroDivendThe retry KeywordThe retry keyword can be used to rerun the block givena certain condition. See text for an example. The readeris warned of the obvious potential of generating infiniteloops.System Errors"System errors are raised when a call to the operatingsystem returns an error code. " - PickAxe" Module Errno is created dynamically to map these operating
system errors to Ruby classes, with each error number generating
its own subclass of SystemCallError. As the subclass is created
in module Errno, its name will start Errno::. " -Ruby Docs
Following are some examples and their numeric values.Exampleputs Errno::EACCES::Errnoputs Errno::EAGAIN::Errnoputs Errno::EPERM::Errnoputs Errno::EIO::Errnoputs Errno::EWOULDBLOCK::Errnoputs Errno::EINTR::Errno
OUTPUT131115100354The raise Keyword, Raising Your Own ExceptionsExceptions can be generated using the raise keyword.This is analogous to how the 'throw' keyword is used inJava.Just running the word, raise in Ruby shows an unhandledexception has occurred.ExampleraiseOUTPUTexception.rb:1:in `<main>': unhandled exception>Exit code: 1If a string is associated with 'raise', a new Runtime exceptionis created with that comment associated with it.Exampleraise "Exception Taken"OUTPUTexception.rb:1:in `<main>': Exception Taken (RuntimeError)>Exit code: 1The begin block can be added to handle an exception thatwas raised explicitly.Examplebeginraise "Exception Taken"rescueputs " There was an exception but it OK! "endOUTPUTThere was an exception but it OK!>Exit code: 0 Creating a Custom Exception Subclass Exceptions can be created by extension to suit a particular need as is shown in the following example. Example class LogicalException < StandardError attr :message def initialize(message) @message = message end end begin if (true) raise LogicalException.new("The \'I always lie\' Paradox") end rescue LogicalException=> er puts er.message end OUTPUT The 'I always lie' Paradox The catch and throw Control in RubyThe catch and throw mechanism is really more a flowcontrol mechanism than part of Ruby's exceptionhandling mechanism. It does not in action parallelthe similarly named keywords in Java.The catch is used to set up a block within which thethrow statement can be used to abandon operationof that block under a given set of conditions.The catch .. throw Formcatch (:label, 2nd_arg_return_ val) {throw:label}Examplecatch (:done) dox=02.times{x+=1; puts "Doing Stuff"}puts xif (x>=2)#increase 'trip value' to 3 and throw won't executethrow :doneend2.times{puts "Doing More Stuff But ..."}endOUTPUTDoing StuffDoing Stuff2Directing Control To an Higher ScopeThe label can be used to direct the resumptionof code to a catch in higher scope as is shownin the following example. ( change the labelassociated with the throw clause to see thedifferent effect on flow control.Examplecatch(:outer){puts "before inner catch"catch (:inner) {puts "before inner label"throw :outer # change to outerputs "after inner label"}puts "after inner catch"}OUTPUTbefore inner catchbefore inner labelafter inner catchReturn ValueThe catch returns nil unless the throw is accompaniedby a second parameter which becomes the return valueas is shown in the example below.Exampleans = catch (:inner) {throw :inner, "inner peace"}string = "Sometimes you can be thrown but still find #{ans}."puts stringOUTPUTSometimes you can be thrown but still find inner peace.Using throw & catch in Some Form of ValidationThe following example from the text shows a throw and catchcombo being used to terminate a program if a specific characteris entered, here an exclamation mark.Example// adapted from Programming Ruby, 1.9.2, Thomas,Fowler & Huntdef prompt_and_get(prompt) print prompt res = readline.chomp throw :quit_requested if res == "!" res end catch :quit_requested do name = prompt_and_get("Name: ") age = prompt_and_get("Age: ") sex = prompt_and_get("Sex: ") # .. # process information end produces => an early termination if ! mark is entered
IO
Much IO capacity is
defined in the Kernel module. The
Kernel module is 'mixed in' to
Object class and so it's
methods are globally available to all classes as
all classes
descend from Object.
"Object
mixes in the Kernel module, making the built-in
kernel functions
globally accessible. " -
Ruby Docs
The
following summary of the Kernel methods shows that
a great
deal of the capability we
have been introduced to
so far in Ruby is defined
in
the
Kernel
module,
which in turn
is part of the Object class.
Kernel
Method Summary
|
Array Complex Float Integer Rational String __callee__ __method__ ` abort at_exit autoload autoload? binding block_given? callcc caller catch chomp chop eval exec exit exit! fail fork format gets global_variables gsub iterator? lambda load local_variables loop open p print printf proc putc puts raise rand readline readlines require select set_trace_func sleep spawn sprintf srand sub syscall system test throw trace_var trap untrace_var warn |
Following are
some of the IO methods from Kernel that we have
used ( and some
others that have yet to be introduced)
Common
IO Methods Defined in Kernel
gets
open
printf
putc
puts
readline
readlines
The output methods
we are use to using might be
prefixed with Kernel.
Example
print
"The puts( ) method is the same as "
Kernel.puts
"Kernel.puts( )"
OUTPUT
The
puts( ) method is the same as Kernel.puts( )
The
Specialized IO Class
IO, standing for Input and Output, is an object that you
read from or write to.
Ruby's IO hierarchy is relatively simple with a base IO
class
providing parentage for File and BasicSocket
classes.
IO
Hierarchy
IO
|_File
|_BasicSocket
Socket
Classes Used for Networking
BasicSocket
is in turn the parent of a set of classes
specialized to make
network connections.
Socket Hierarchy
BasicSocket
|
|_Socket
|_IPSocket
|
|_UDPSocket
|
|_TCPSocket
|
|_TCPServer
|
|_UNIXServer
|
|_UNIXServer
|
|_SocketError
// there is an Addrinfo class in the package as well
The File Class
The first thing that is done with a file is to open
it.
Eventually you will also need to close it. This
action is
encapsulated in the File constructor.
Example //
File opens in default read mode
file = File.new("Milton")
# process file
file.close
# same as
file = File.new("Milton", "r")
# process
file
file.close
Following are different
modes available.
Ruby
Read Write Modes
//
adapted from Tutorial Points,
http://www.tutorialspoint.com/ruby/ruby_input_output.htm
|
Modes |
Description |
|---|---|
|
r |
Read-only, the default. The file pointer is at the beginning of the file. |
|
r+ |
Read-write mode. The file pointer is at the beginning of the file. |
|
w |
Write-only, overwrites file if it exists. If not, creates a new writeable file |
|
w+ |
Read-write, overwrites file if it exists. If not creates a new read-write file |
|
a |
Write-only mode. The file pointer is at the end of the file if it exists and is in append mode. If the file does not exist, it creates a new file for writing. |
|
a+ |
Read and write mode. The file pointer is at the end of the file if it exists in append mode. If the file does not exist, it creates a new read-write file |
These values can also be represented by the following
constants.
For the complete list see page 506, in Programming Ruby
1.9x.
Read Write Mode Constants
// see page 506, PickAxe
File::APPEND # writes to end of file.
File::CREAT # creates file if it doesn't exist.
File::EXCL # used with File::CREAT, opens fails if file exists.
File::RDONLY # read only.
File::RDWR # read & write
File::TRUNC # Opens file and truncates to zero length if it exists.
File::WRONLY # write only.
Example
file
= File.new("Milton.txt", File::APPEND)
file.close
File.open
and
File.new
File.open
opens a file just as File.new does. If a block
is supplied to
File.open, the opened file is passed to
the block as a parameter.
When the block returns the
file is closed, even if an exception is
raised within the
block.
Example// from Programming Ruby, 1.9.2, Thomas,Fowler & Hunt
File.open("testfile",
"r") do |file|
#
... process the file
end
# <-
file automatically closed here
With
File.new closing the file is your responsibility,
This would
typically be done in an 'ensure' clause
clause of a begin
block.
The
gets(
)
Method
The
gets( ) method reads a line from the file object.
Example
file
= File.new("Milton.txt", "r+")
first_line =
file.gets
puts first_line
file.close
OUTPUT
"Paradise
Lost
is
an
epic
poem in blank verse by the 17th-century English poet
John Milton.
We
saw earlier the form of the while statement that
allows reading
the whole file. It is nice as the gets( )
method runs until it
returns nil which breaks the while
loop.
Example
while
line = gets
puts line
end
Adding the loop to the above
example yields the following.
Example
file
= File.new("Milton.txt", "r+")
while line =
file.gets
puts line
end
file.close
OUTPUT
"Paradise
Lost
is
an
epic
poem in blank verse by the 17th-century English poet
John Milton.
It was originally published in 1667 (though written
nearly ten years earlier) in ten books, with
a total of over ten
thousand individual lines of verse. A second edition followed in
1674,
redivided into twelve books (in the manner of the division
of Virgil's Aeneid) with minor
revisions throughout and a note on
the versification; the majority of the poem was written
while
Milton was blind, and was transcribed for him." - wikipedia
Reading
Iterators
In
the next example, from the text, the each_byte( ) method
reads
off 8-bit bytes. Indexes are used to decide how many
characters
are processed. The block processes the output
to ASCII characters
plus it's integer value.
Example// from Programming Ruby, 1.9.2, Thomas,Fowler & Hunt
File.open("testfile")
do |file|
file.each_byte.with_index
do |ch, index|
print
"#{ch.chr}:#{ch} "
break
if index > 10
end
end
produces:
T:84
h:104 i:105 s:115 :32 i:105 s:115 :32 l:108 i:105 n:110 e:101
The
dump( ) Method
String
has a dump method which works with lines to reveal
newline
characters. Notice it does not reveal the other escapes
included. To
focus attention on the method, the example is simply
executed on
a string.
Example
string
= "\n The string with \'newlines\' \n"
puts
string
puts
string.dump
OUTPUT
The
string with 'newlines'
"\n
The string with 'newlines' \n"
Using
Characters as Line Separators
The
character that is used to delineate lines can
be arbitrarily set
via the each_line( ) method as
is shown in the following. Some
text is supplied
for the file. The line separator selected
is the
vertical bar.
Sample
Text For a Test File //
save as 'night'
The
night is long. | I have been waiting since seven. |
There
is not a Tim Horton's here. | Worse, I gave up drinking coffee.|
Tic!
Toc! Goes the clock! |
Example
File.open("night")
do |file|
file.each_line("|")
{|line| puts line.dump }
end
OUTPUT
"The
night is long. |"
"
I have been waiting since seven. |"
"\nThere
is not a Tim Horton's here. |"
"
Worse, I gave up drinking coffee.|"
"\nTic!
Toc! Goes the clock! |"
"\n"
The
for_each Method
"
If you combine the idea of an iterator with the auto-closing
block
feature, you get IO.foreach. This
method takes the name
of an I/O source, opens it for reading,
calls the iterator once for
every
line in the file, and then closes the file automatically: "
- Programming Ruby 1.92
This
is shown in the following text example.
Example// from Programming Ruby, 1.9.2, Thomas,Fowler & HuntIO.foreach("testfile") {|line| puts line }
produces:
This
is line one
This
is line two
This
is line three
And
so on...
Putting
a File's Content Into a String
Ruby
makes it simple to put the entire contents of a
file
into a string as shown in the next example.
s
= IO.read("Milton.txt")
puts
s.length
puts
s
OUTPUT
//
condensed
"Paradise
Lost is an . . . transcribed for him."
- wikipedia
Putting
a Files Content Into an Array Using readlines( )
IO
class has a readlines( ) method that is useful for
changing the
contents of a file to an array where each
element of the array
holds a line.
arr
= IO.readlines("testfile")
arr.length
# => 4
arr[0]
# => "This is line one\n"
#
results in an array with one line per element
OUTPUT
//
last line condensed
4
the
majority of the poem . . . was transcribed for him." -
wikipedia
Writing
to File
The
following is an example of appending a comment to
the
Milton file.
Example
File.open("milton.txt",
"a") do |file|
file.puts
"\n\n Comments \n\n"
file.puts
"Really enjoyed the blurb on Milton - Tony Mills"
end
OUTPUT
// See the milton text
file
Behind
The Scenes With the puts( ) and print( ) Methods
When
an object is being put to console with one these output
methods
normally the to_s( ) method is called on the object.
If
nothing meaningful is defined for to_s( ), the the objects UID
is
printed to screen.
Two
Special Cases
//
using puts
the nil object prints an empty string to screen
An array passes an element per line to screen
Example
array
=[ :a, :b, :c]
puts
array
puts
nil
puts
"A_line_under_an_empty_string"
#
puts nil outputs an empty
string
OUTPUT
a
b
c
A_line_under_an_empty_string
Writing
Binary Into a String
The
text shows a number of ways to do this in it's
example.
Example// from Programming Ruby, 1.9.2, Thomas,Fowler & Hunt
str1 = "\001\002\003" # => "\x01\x02\x03"
str2 = ""
str2
<< 1 << 2 << 3 #
=> "\x01\x02\x03"
[
1, 2, 3 ].pack("c*") #
=> "\x01\x02\x03"
Appending
to Standard Output
The
text has the following interesting example.
Example// from Programming Ruby, 1.9.2, Thomas,Fowler & Hunt
endl = "\n"
STDOUT
<< 99 << " red balloons" << endl
OUTPUT
99
red balloons
The
<< , Left Shift Operator //
the append operator
It
is noted that the append operator is very handy as it
is
overridden for different object types. It therefore can
be used without a lot of concern if it adds to an array,
file
or string. This
makes it good for testing.
The
StringIO Class
At
this point the text introduces us to the StringIO class.
The
documentation for the class, is very scant, offering
only that it allows "pseudo
I/O on a String object".
The
class is the only resident of the 'stringio' package so to
use
it, this package is required.
The
class allows a string to be treated in a manner similar
to
a file.
The
example, modified slightly from the text, shows us this
approach.
Example// adapted from Programming Ruby, 1.9.2, Thomas,Fowler & Hunt
require 'stringio'
ip
= StringIO.new("Now is\nthe time\nto learn\nRuby!\n\n")
op
= StringIO.new("", "w")
ip.each_line do
|line|
op.print line.reverse
end
print op.string
OUTPUT
si
woN
emit eht
nrael ot
!ybuR
Networking
IO
//
Class details are supplemental and are not required learning
Ruby
supplies all the classes one needs to develop networking
programs.
Networks are based on connections which in turn
are implemented
in socket technology, originally developed
at Berkley in the 80s.
// with 4.2BSD Unix operating system, released in 1983
Following are the
Networking Subclasses of BasicSocket with
a
brief description of what they do.
Socket
Classes With Descriptions
BasicSocket
abstract base class for socket classes
UNIXSocket
provides IPC using the UNIX domain protocol
(AF_UNIX)
UNIXServer
helper for building UNIX domain protocol socket servers
IPSocket Base
for protocols using the Internet Protocol (AF_INET)
UDPSocket
for User Datagram Protocol (UDP) sockets
TCPSocket
for Transmission Control Protocol (TCP) sockets
TCPServer Helper
for building TCP socket servers
SOCKSSocket
helper for building SOCKS-based sockets applications
Socket
Base socket class that mimics that BSD Sockets API
| SOCKS A protocol for handling TCP traffic through a proxy server. It can be used with virtually any TCP application, including Web browsers and FTP clients. It provides a simple firewall because it checks incoming and outgoing packets and hides the IP addresses of client applications. -Webopedia http://www.webopedia.com/TERM/S/SOCKS.html |
INSERT:
Class
Methods
in Ruby
The
IBM paper referenced in this note uses the double colon
notation, :: to reference class
methods. We have to this point
only been instructed to use this
notation in referencing variables
defined in modules. Following
is the notation used to describe
a Socket class method in the IBM
Networking paper.
Example
Socket::gethostname
Fortunately
in testing, the form of referencing a class method
via the
class name and the dot operator also works. Following
is an
example from the
IBM paper run using irb.
Example
>irb
irb(main):001:0>
require 'socket'
=>
true
irb(main):003:0>
IPSocket::getaddress('www.ibm.com')
=>
"129.42.56.216"
The
next example shows we can sub in the single dot reference
form.
Example
showing dot Notation Working as Well
irb(main):004:0>
IPSocket.getaddress('www.sentex.net')
=>
"98.159.240.6"
How
to Create Class Methods
The
following example from the 'RubyTips's site shows class
methods
are created by defining them explicitly using the 'self'
keyword.
|
Defining Class Methods Example // from RubyTips, see url above class
Foo |
Taking
the
lead
from
the
IBM paper, details are provided
for the more
common classes of the collection, namely
Socket, UDPSocket,
TCPSocket and TCPServer.
//
you might want to add IPSocket
Socket
Class
The
Socket class is encapsulates the BSD Sockets API. Standard
functions include accept, bind, listen and connect among
others.
Socket
Constructor
Socket::new(domain, type, proto)
Creates a new socket
Following is a
partial list of methods.
Socket
Class Methods
//
prefix methods in use as in Socket::for_fd(fd)
for_fd(fd)
returns a Socket object for the passed file descriptor
gethostbyaddr(addr[, type])
resolves the IP address to a fully qualified domain name
gethostbyname(name)
resolves the host name to an IP address
gethostname
returns a string representing the hostname
Socket
Instance Methods
bind(addr)
binds the socket to the packed address string
listen(backlog)
places the socket into the listening state,
with a number of outstanding requests set to backlog
accept
accepts a new connection (returns a new socket)
connect(addr)
connects the socket to the host defined
by thepacked address string
recvfrom(len[, flags])
Receives data (up to len in size) from the socket,
returns a string containing the data and peer address
UDPSocket
The
UDPSocket class implements the connectionless User
Datagram
Protocol. UDP is
used in the Domain Name Service
(DNS) protocol, the Dynamic Host
Configuration Protocol
(DHCP), the Service Location Protocol
(SLP), the Network
Time Protocol (NTP), and the Trivial File
Transport Protocol
(TFTP).
UDP
is fast as it is does not guarantee receipt of data as does
TCP.
It is good for
services that merely retransmit after a certain
time out.
UDPSocket
Constructor
UDPSocket::new
creates a new UDPSocket object
UDP
Instance Methods
bind(host, port)
binds the UDP socket instance to the port on the host
connect(host, port)
connects UDP socket to the port on the host
sock.send(mesg, flags[, dest])
sends data (mesg) on the UDP socket to thedestination
The examples show
how remarkably brief the code is to create
clients
and servers. This example is quite simple, yet it does
speak
to the power of Ruby to do things in a succinct manner.
Run
the following on separate DOS terminals starting the server
first. Watch the
Server window as you start the client. It signals
the
server 5 times before the server retires.
Example
//
from LeeJava Wordpress,
http://leejava.wordpress.com/2009/08/24/udp-client-and-server-in-ruby/
Server
Example
require
'socket'
s
= UDPSocket.new
s.bind(nil,
1234)
5.times
do
text,
sender
=
s.recvfrom(16)
puts
text
end
Client
Example
require
'socket'
s =
UDPSocket.new
s.send("hello",
0, 'localhost', 1234)
TCPSocket
and
TCPServer
classes
The
TCP Transmission Control Protocol is described as a
connection-based,
and 'reliable' Transmission Control Protocol.
It
goes one step beyond UDP in providing a guarantee that
data
is received by the target receiver.
While
UDP is like regular mail, TCP is more like registered mail.
This
all comes from fact that in TCP a sender of a data packet
waits
to be notified that the packet has been received by the
recipient.
If the acknowledgment isn't received, the data is
sent
again.
The
TCPSocket class supports the 'reliable' Transmission Control
Protocol. A
helper class for the creation of TCP server sockets
is
also available in the TCPServer class
TCPSocket
and TCPServer Constructors
TCPSocket::new(host, service)
Creates a new TCPSocket object
TCPServer::new(host, service)
Creates a new TCPServer object
TCPSocket
and TCPServer Instance Methods
gethostbyname(host)
returns an array with the canonical name, aliases, protocol
domain, and dotted IP address for the resolved hostname
accept
waits for a client connection and
returns a new TCPSocket object
The following is a
simple TCP Client Server Example where
the
server sends the client the time. Run the server first in one
DOS
window.
TCP
Server Example
//
adapted from example at Tutorial Points, see references for URL
require
'socket'
server =
TCPServer.open(23456)
loop
{
client =
server.accept
client.puts(Time.now.ctime)
client.puts
"Over & out!"
client.close
}
TCP
Client
require
'socket'
s =
TCPSocket.open('127.0.0.1', 23456)
while
line = s.gets
puts
line.chop
end
s.close
Parsing
HTML
The
text points out that regular expressions can be used
to
parse HTML, but it is not as easy a task as one might
one to deal
with. Following is an example of a regular
expression based
parse.
Example// from Programming Ruby, 1.9.2, Thomas,Fowler & Hunt
require 'open-uri'
page
=
open('http://pragprog.com/titles/ruby3/programming-ruby-1-9').read
if
page =~ %r{<title>(.*?)</title>}m
puts "Title is
#{$1.inspect}"
end
OUTPUT
Title
is "The Pragmatic Bookshelf | Programming Ruby 1.9"
The
Hpricot Library
Ruby
developers supply a superior package that is very popular
called
the Hpricot library that is especially designed to parse HTML.
The
following example from the text shows how it is used. You
will
need to go through
some extra installs in order to try the
library out.
Example// from Programming Ruby, 1.9.2, Thomas,Fowler & Hunt
require 'open-uri'
require
'hpricot'
page =
Hpricot(open('http://pragprog.com'))
puts
"Page title is " + page.at(:title).inner_html
#
Output the first paragraph in the div with an id="copyright"
puts
page.at('div#copyright p')
#
Output the second hyperlink in the site-links div
puts
"\nSecond hyperlink is"
puts
page.at('div#site-links a:nth(2)')
Assignment
Q.1 Use subclassing
to create an exception that is
fired
when a catastrophe is imminent at a nuclear power
plant.
Throw the exception using the raise command
and capture
it in a begin block's rescue clause.
( An example is provided
below. )
Q.2 Create an exception class that extends RuntimeError
and is designed to carry a message. Raise the exception
in a begin block so that in the rescue block the message
is put to console. (Refer to the example used in Q. 1)
Q.3 Use the example below or do from a clean sheet a
nested catch throw where on a condition that is reached
the outer catch is labelled so it is terminated.
Q.4 For the record, use the classic while loop to put some
verse stored in a File to console. Then use a writing method
to add a comment to the file. Then again, use a while loop
to show the file contents with the comment appended.
Q.5 Using the examples below, where the UDP example sends
something to the server and the TCP examples sends something
back to the client, create a client server program that on sending
your name, the server sends back a day account number for a
convention.
The servers sends something like "Hello Harry Smith! Your day
account number is 1234567." ( Make it a bit real by using
an
increment operation to ensure different account numbers are
given to each person.)
Question
Examples
// examples are from text above
Q.1
& 2 Example
class LogicalException < StandardError attr :message def initialize(message) @message = message end end
begin if (true) raise LogicalException.new("The \'I always lie\' Paradox") end rescue LogicalException=> er puts er.message end
OUTPUT
The 'I always lie' Paradox
Q.3 ExamplesThe catch .. throw Formcatch (:label, 2nd_arg_return_ val) {throw:label}
Example
File.open("milton.txt",
"a") do |file|
file.puts
"\n\n Comments \n\n"
file.puts
"Really enjoyed the blurb on Milton - Tony Mills"
endExamplecatch (:done) dox=02.times{x+=1; puts "Doing Stuff"}puts xif (x>=2)#increase 'trip value' to 3 and throw won't executethrow :doneend2.times{puts "Doing More Stuff But ..."}end
Q.4 Example
file
= File.new("Milton.txt", "r+")
while line =
file.gets
puts line
end
file.close
Q.5 Examples TCP Server Example
//
adapted from example at Tutorial Points, see references for URL
require 'socket'
server =TCPServer.open(23456)
loop{
client =server.accept
client.puts(Time.now.ctime)
client.puts "Over & out!"
client.close
}
TCP
Client
require 'socket'
s =TCPSocket.open('127.0.0.1', 23456)
while line = s.gets
puts line.chop
end
s.close
Example
//
from LeeJava Wordpress,
http://leejava.wordpress.com/2009/08/24/udp-client-and-server-in-ruby/
UDP Server
Example
require 'socket'
s= UDPSocket.news.
bind(nil,1234)
5.times do
text, sender = s.recvfrom(16)
puts text
end
UDP Client
Example
require
'socket'
s =
UDPSocket.new
s.send("hello",
0, 'localhost', 1234)