Updated code examples from the examples in the EiffelStudio distribution. Updated discussion to reflect changes in code.

Author:halw
Date:2012-04-22T19:59:12.000000Z


git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@1078 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
halw
2012-04-22 19:59:12 +00:00
parent 9841610b56
commit 38424d162f

View File

@@ -14,12 +14,12 @@ In EiffelNet the possible events associated with a socket will be of three kind:
===9.2 Command classes=== ===9.2 Command classes===
The example uses four command classes: <code>CLIENT_DATAGRAM_READER</code>, <code>CLIENT_DATAGRAM_WRITER</code> and their counterpart for servers, representing operations that must be triggered in the case of a read event and a write event. The example uses three command classes: <code>DATAGRAM_READER</code>, used by both clients and servers, and specialized versions of a datagram writer for clients, <code>CLIENT_DATAGRAM_WRITER</code>, and servers, <code>SERVER_DATAGRAM_WRITER</code>. These classes model operations that must be triggered in the case of a read event and a write event.
Here is the reader command for clients: Here is the common reader command:
<code> <code>
class class
CLIENT_DATAGRAM_READER DATAGRAM_READER
inherit inherit
@@ -29,39 +29,37 @@ inherit
end end
create create
make make
feature feature
active_medium: NETWORK_DATAGRAM_SOCKET active_medium: NETWORK_DATAGRAM_SOCKET
execute execute (arg: ANY)
-- Obtain a packet of ten characters and print them.
local local
rec_pack: DATAGRAM_PACKET rec_pack: PACKET
datagram: DATAGRAM_PACKET
i: INTEGER i: INTEGER
do do
rec_pack := active_medium.received (10, 0) rec_pack := active_medium.received (10, 0)
io.putint (rec_pack.packet_number) create datagram.make_from_managed_pointer (rec_pack.data)
io.putint (datagram.packet_number)
io.new_line io.new_line
from from i := 0 until i > 9 loop
i := 0 io.putchar (datagram.element (i))
until
i > 9
loop
io.putchar (rec_pack.element (i))
i := i + 1 i := i + 1
end end
io.new_line io.new_line
end end
end end -- class DATAGRAM_READER
</code> </code>
The <eiffel>execute</eiffel> procedure reads a packet of ten characters and prints these characters. Its counterpart in the writing command will produce these ten packets: The <eiffel>execute</eiffel> procedure reads a packet of ten characters and prints these characters. Its counterpart in the writing command will produce these ten packets:
<code> <code>
class class
CLIENT_DATAGRAM_WRITER CLIENT_DATAGRAM_WRITER
inherit inherit
@@ -71,35 +69,30 @@ inherit
active_medium active_medium
end end
BASIC_ROUTINES
create create
make make
feature feature
active_medium: NETWORK_DATAGRAM_SOCKET active_medium: NETWORK_DATAGRAM_SOCKET
execute execute (arg: ANY)
-- Make a packet with characters 'a' to 'k' in successive positions.
local local
sen_pack: DATAGRAM_PACKET sen_pack: DATAGRAM_PACKET
ccode: INTEGER char: CHARACTER
do do
-- Make packet with characters `a' to `j' in successive positions
create sen_pack.make (10) create sen_pack.make (10)
from from char := 'a' until char > 'j' loop
ccode := charcode ('a') sen_pack.put_element (char, char |-| 'a')
until char := char.next
ccode > charcode ('k')
loop
sen_pack.put_element (charconv (ccode), ccode -- charcode ('a'))
ccode := ccode + 1
end end
sen_pack.set_packet_number (1) sen_pack.set_packet_number (1)
active_medium.send (sen_pack, Void, 0) active_medium.send (sen_pack, 0)
end end
end end -- class CLIENT_DATAGRAM_WRITER
</code> </code>
===9.3 The server and the client=== ===9.3 The server and the client===
@@ -110,71 +103,84 @@ The abstraction needed for this purpose is provided by class <code>MEDIUM_POLLER
Here is the server built with this mechanism: Here is the server built with this mechanism:
<code> <code>
class class
POLLING_SERVER POLLING_SERVER
create create
make make
feature feature
make make (argv: ARRAY [STRING])
-- Create read and write commands, attach them to a poller,
-- set up the poller for execution.
local local
soc: NETWORK_DATAGRAM_SOCKET soc: detachable NETWORK_DATAGRAM_SOCKET
poller: MEDIUM_POLLER ps: MEDIUM_POLLER
readcomm: SERVER_DATAGRAM_READER readcomm: DATAGRAM_READER
writecomm: SERVER_DATAGRAM_WRITER writecomm: SERVER_DATAGRAM_WRITER
do do
create soc.make_server_by_port (6530) if argv.count /= 2 then
create poller.make io.error.putstring ("Usage: ")
create readcomm.make (soc); poller.put_read_command (readcomm) io.error.putstring (argv.item (0))
create writecomm.make (soc); poller.put_write_command (writecomm) io.error.putstring (" portnumber%N")
poller.make_read_only; poller.execute (15, 20000) else
poller.make_write_only; poller.execute (15, 20000) create soc.make_bound (argv.item (1).to_integer)
soc.close create ps.make_read_only
create readcomm.make (soc)
ps.put_read_command (readcomm)
create writecomm.make (soc)
ps.put_write_command (writecomm)
ps.execute (15, 20000)
ps.make_write_only
ps.execute (15, 20000)
soc.close
end
rescue
if soc /= Void and then not soc.is_closed then
soc.close
end
end end
end end -- POLLING_SERVER
</code> </code>
Procedure <eiffel>make</eiffel> creates three objects: a socket, which it associates with a specific port; a poller; and a read command (an instance of SERVER_DATAGRAM_READER), which it attaches to the socket. It then enters the read command into the poller, and does the same thing with a write command. It sets up the poller to accept read commands only and then executes the poller; this will enable the server to get the read event triggered by the client's write command (as it appears below in the text of class <code>POLLING_CLIENT</code>). Then the server reverses the poller's set-up to write-only, and calls <eiffel>execute</eiffel> again. Procedure <eiffel>make</eiffel> creates three objects: a socket, which it associates with a specific port; a poller; and a read command (an instance of DATAGRAM_READER), which it attaches to the socket. It then enters the read command into the poller, and does the same thing with a write command. It sets up the poller to accept read commands only and then executes the poller; this will enable the server to get the read event triggered by the client's write command (as it appears below in the text of class <code>POLLING_CLIENT</code>). Then the server reverses the poller's set-up to write-only, and calls <eiffel>execute</eiffel> again.
The procedures <eiffel>make_read_only</eiffel> and <eiffel>make_write_only</eiffel> are creation procedures, so that it is possible in a single instruction to create a poller and set it up for read-only or write-only, as in <eiffel>create poller.make_read_only</eiffel>. For clarity, however, the above class and the next separate calls to these procedures from the creation of the poller, which uses <eiffel>make</eiffel> as creation procedure.
The client follows the same scheme, reversing the order of read and write operations: The client follows the same scheme, reversing the order of read and write operations:
<code> <code>
class class
POLLING_CLIENT POLLING_CLIENT
create create
make make
feature feature
make make (argv: ARRAY [STRING])
-- Create read and write commands, attach them to a poller,
-- set up the poller for execution.
local local
soc: NETWORK_DATAGRAM_SOCKET soc: detachable NETWORK_DATAGRAM_SOCKET
poller: MEDIUM_POLLER ps: MEDIUM_POLLER
readcomm: DATAGRAM_READER readcomm: DATAGRAM_READER
writecomm: DATAGRAM_WRITER writecomm: CLIENT_DATAGRAM_WRITER
do do
create soc.make_client_by_port (6530, "serverhost") if argv.count /= 3 then
create poller.make io.error.putstring ("Usage: ")
create readcomm.make (soc) io.error.putstring (argv.item (0))
poller.put_read_command (readcomm) io.error.putstring (" hostname portnumber%N")
create writecomm.make (soc) else
poller.put_write_command (writecomm) create soc.make_targeted (argv.item (1), argv.item (2).to_integer)
poller.make_write_only create ps.make_write_only
poller.execute (15, 20000) create readcomm.make (soc)
poller.make_read_only ps.put_read_command (readcomm)
poller.execute (15, 20000) create writecomm.make (soc)
soc.close ps.put_write_command (writecomm)
ps.execute (15, 20000)
ps.make_read_only
ps.execute (15, 20000)
soc.close
end
rescue rescue
if soc /= Void and then not soc.is_closed then if soc /= Void and then not soc.is_closed then
soc.close soc.close