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!
Non-blocking Output Socket @ MATLAB Central
The Problem
As 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.
OutputSocket
OutputSocket 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()
ListeningThread
The 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()
Interaction
The 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 MATLAB
Place the .class files in a suitable location (I've stuck them in my current working directory).
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.>> % 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
**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.
Hello Rodney,
ReplyDeleteFirst of all, I want to thank you for sharing your code with the community.
I am using your code to do communication between a software written in C and Matlab.
I have a question, how can I change the client.m to execute a Matlab command and not just to show it in the command window.
Thank you for help
Hi Rodney,
ReplyDeleteThank you very much for sharing the code and I'm really appreciate for your kindness.
I have tried your code and some questions about sending and reading the data over the socket.
If let's say I have a byteArray variable and I like to send this variable to the server, is that possible?
If possible, then how the server read the data from the byteArray?
Guess that's all. Thank you once again for sharing the knowledge.
Thank you
Hi Rodney,
ReplyDeleteI licked very much your non blocking socket because I had been to do the same without success. In my case I would need that once the ListeningThread is running , it would launch a matlab program. I mean, the OutputSocket wrapper is caed in matab and I need that when a new connection is detected, it starts to run a new matlab program/thread. Do tou think is possible by using your code and little changes?
Thank you for hep!