My
MATLAB TCP/IP example has been quite popular, and I myself use it at least once a week on various applications. However, one of the main limitations when compared to our C++ style output sockets was the limitation of only 1 client per socket.
What was worse, is that I knew it COULD be done. I had just not found the time to write it! Cue a spare Saturday!
The ProblemAs per my previous server.m examples, you begin by constructing a Java
ServerSocket.
>> server_socket = ServerSocket(output_port);
>> server_socket.setSoTimeout(1000);
This attempts to bind the
ServerSocket to the specified port. HOWEVER, it is not listening for incoming connections! To do this, you must tell the
ServerSocket to
accept().
>> output_socket = server_socket.accept();
This is a BLOCKING call. That is, the code will wait for either the timeout (set above) to occur, or a client to connect.
For a lot of what I do, the output socket exists mainly as a debugging / monitoring interface. So I don't even care if noone is listening. So what we need is something that manages the connection of clients and the distribution of any written data to each of them.
Enter
OutputSocket and
ListeningThread.
OutputSocketOutputSocket provides a very simple interface:
//---------------------------------------------------------------------
// Description : Create an OutputSocket on the specified port
//---------------------------------------------------------------------
public OutputSocket(int port) throws IOException
//---------------------------------------------------------------------
// Description : Write the supplied byte array to all connected clients
//---------------------------------------------------------------------
public void write(byte[] data)
//---------------------------------------------------------------------
// Description : Close the OutputSocket. This closes all client
// connections and stops listening for new connections.
//---------------------------------------------------------------------
public void close()
ListeningThreadThe
OutputSocket utilises
ListeningThread to manage the accepting of new connections.
ListeningThread implements the
Runnable interface so can be started in its own thread (vital!).
//-------------------------------------------------------------------------
// Description : Helper class that listens for new TCP/IP client
// connections on a ServerSocket
//
// Parameters : server_socket - ServerSocket to listen on
// connection_list - List of connected client
// Sockets to update
// connection_stream_list - List of connected client
// DataOutputStreams to update
//---------------------------------------------------------------------
public ListeningThread(ServerSocket server_socket,
List connection_list,
List connection_stream_list)
//---------------------------------------------------------------------
// Description : Called on Thread.start()
//---------------------------------------------------------------------
public void run()
//---------------------------------------------------------------------
// Description : Stop the thread
//---------------------------------------------------------------------
public void stop()
InteractionThe
OutputSocket constructor creates the
ServerSocket as before and stores it as a member variable. It also creates 2 empty lists, one for the
Socket client connections and one for the associated
DataOutputStreams used to write to them.
It supplies a reference to these to the
ListeningThread on construction and then starts it running in its own
Thread. This is the important part.
OutputSocket and
ListeningThread both share a reference to the
DataOutputStream list, so as
ListeningThread creates connections and output streams, these are pushed onto the client list.
When
OutputSocket::write() is called, it writes the data across all output streams (be there 0 or 100!)
When you have finished with the
OutputSocket, a call to
close() will stop the
ListeningThread from running and close all client connections.
Usage from within MATLABPlace the .class files in a suitable location (I've stuck them in my current working directory).
>> % Add the directory containing the .class files to your Java path
>> javaaddpath(pwd)
>> % Create the OutputSocket
>> output_socket = OutputSocket(1234)
output_socket =
OutputSocket@1c68b20
>> % Write some data to the output socket - text will do for now
>> for i = 1:100
output_socket.write(int8(sprintf('This is line %03d\r\n', i)));
pause(1);
end
>> % cleanup the socket - close connections
>> output_socket.close()
>> clear output_socket % no longer needed / useful
As you can see, multiple connections are supported. They can connect/disconnect at any time. Even if there are no connections, a call to
OutputSocket::write() will be successful.
**Update**I've included in the revised submission to MATLABCentral a wrapper MATLAB class that helps manage the lifetime of the Java object.
This is VERY useful because if you happen to clear the Java object (ie
clear output_socket) before calling
.close() the
Thread and
ServerSocket etc remain in memory (and stay connected!) until MATLAB is closed!
Suggested usage of
MatlabOutputSocket below.
>> javaaddpath(pwd); % get the Java class
>> output_socket = MatlabOutputSocket(1234);
for i = 1:100
output_socket.write(int8(sprintf('Line %03d\r\n', i)));
pause(1);
end
>> output_socket.close()
>> clear output_socket
I've included the Java source file in the MATLABCentral submission, so feel free to have a look at the source code, have a fiddle, recompile.
To do this you will need to install the
Java Development Kit (JDK).
To compile the classes, navigate to the directory containing the .java file and type:
>> javac OutputSocket.java
NOTE: You will have to repeat the call to javaaddpath() for the new files to be seen by MATLAB.