While lock-step mode is acceptable for dialing a modem, it breaks down when you have two independent agents communicating over a port. Either end may be a person, as in a remote login session, or a program, either a server or a client program. A client program, in turn, may be driven by a person (as is a web browser) or may be self-driven (such as an FTP client transferring many files at one request). You cannot predict, then, who will need to read and who will need to write. Consider the simplest case: the programs at both end try to read at the same time! Using the lock-step model, each end will wait forever for the other end to write something. This error condition is known as a deadlock , since both ends are locked up, dead, until a person intervenes, or the communication line drops, or the world ends, or the universe ends, or somebody making tea blows a fuse and causes one of the machines to halt.
There are two general approaches to this problem: event-driven activity, wherein the Communications API notifies you when the port is ready to be read or written, and threads-based activity, wherein each “direction” (from the user to the remote, and from the remote to the user) has its own little flow of control, causing only the reads in that direction to wait. We’ll discuss each of these.
First, Example 11-7 reads from a serial port using the event-driven approach.
Example 11-7. SerialReadByEvents.java
import java.awt.*; import java.io.*; import javax.comm.*; import java.util.*; /** * Read from a Serial port, notifying when data arrives. * Simulation of part of an event-logging service. */ public class SerialReadByEvents extends CommPortOpen implements SerialPortEventListener { public static void main(String[] argv) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { new SerialReadByEvents(null).converse( ); } /* Constructor */ public SerialReadByEvents(Frame f) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { super(f); } protected BufferedReader ifile; /** * Hold the conversation. */ protected void converse( ) throws IOException { if (!(thePort instanceof SerialPort)) { System.err.println("But I wanted a SERIAL port!"); System.exit(1); } // Tell the Comm API that we want serial events. ((SerialPort)thePort).notifyOnDataAvailable(true); try { ((SerialPort)thePort).addEventListener(this); } catch (TooManyListenersException ev) { // "CantHappen" error System.err.println("Too many listeners(!) " + ev); System.exit(0); } // Make a reader for the input file. ifile = new BufferedReader(new InputStreamReader(is)); // } public void serialEvent(SerialPortEvent ev) { String line; try { line = ifile.readLine( ); if (line == null) { System.out.println("EOF on serial port."); System.exit(0); } os.println(line); } catch (IOException ex) { System.err.println("IO Error " + ex); } } }
As you can see, the serialEvent( )
method does the
readLine( )
calls. “But wait!” I hear
you say. “This program is not a very meaningful example. It
could just as easily be implemented using the lock-step method of
Section 11.6. True enough, gentle reader. Have
patience with your humble and obedient servant. Here is a program
that will read from each and any of the serial ports, whenever data
arrives. The program is representative of a class of programs called
"
data loggers,” which receive data
from a number (possibly a large number) of remote locations, and log
them centrally. One example is a burglar alarm monitoring station,
which needs to log activities such as the alarm being turned off at
the close of the day, entry by the cleaners later, what time they
left, and so on. And then, of course, it needs to notify the operator
of the monitoring station when an unexpected event occurs. This last
step is left as an exercise for the reader.
Example 11-8 makes use of the
EventListener
model and uses a unique instance of
the inner class Logger
for each serial port
it’s able to open.
Example 11-8. SerialLogger.java
import java.io.*; import javax.comm.*; import java.util.*; /** * Read from multiple Serial ports, notifying when data arrives on any. */ public class SerialLogger { public static void main(String[] argv) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { new SerialLogger( ); } /* Constructor */ public SerialLogger( ) throws IOException, NoSuchPortException, PortInUseException, UnsupportedCommOperationException { // get list of ports available on this particular computer, // by calling static method in CommPortIdentifier. Enumeration pList = CommPortIdentifier.getPortIdentifiers( ); // Process the list, putting serial and parallel into ComboBoxes while (pList.hasMoreElements( )) { CommPortIdentifier cpi = (CommPortIdentifier)pList.nextElement( ); String name = cpi.getName( ); System.out.print("Port " + name + " "); if (cpi.getPortType( ) == CommPortIdentifier.PORT_SERIAL) { System.out.println("is a Serial Port: " + cpi); SerialPort thePort; try { thePort = (SerialPort)cpi.open("Logger", 1000); } catch (PortInUseException ev) { System.err.println("Port in use: " + name); continue; } // Tell the Comm API that we want serial events. thePort.notifyOnDataAvailable(true); try { thePort.addEventListener(new Logger(cpi.getName( ), thePort)); } catch (TooManyListenersException ev) { // "CantHappen" error System.err.println("Too many listeners(!) " + ev); System.exit(0); } } } } /** Handle one port. */ public class Logger implements SerialPortEventListener { String portName; SerialPort thePort; BufferedReader ifile; public Logger(String name, SerialPort port) throws IOException { portName = name; thePort = port; // Make a reader for the input file. ifile = new BufferedReader( new InputStreamReader(thePort.getInputStream( ))); } public void serialEvent(SerialPortEvent ev) { String line; try { line = ifile.readLine( ); if (line == null) { System.out.println("EOF on serial port."); System.exit(0); } System.out.println(portName + ": " + line); } catch (IOException ex) { System.err.println("IO Error " + ex); } } } }
3.142.212.160