Tuesday, August 19, 2008

TCP/IP Socket Communications in MATLAB

I often see people asking about network communications on the MATLAB Newsgroup. Often this is for the communication between instances of MATLAB.

Using the ability to call Java directly from within MATLAB, I'm going to provide a short example of a client/server written solely in MATLAB and usable from Release 14 onwards (possibly even earlier).

The example is available on the Mathworks File Exchange: Simple TCP/IP Socket Comms Example

I'm working on a little TCP/IP comms library at the moment using these techniques. It will provide a nice layer of abstraction and allow you to use Sockets as you would in other programming languages (as well as one can in a single thread). Keep an eye out for it on the File Exchange.

Interpreted Java?

Amazingly we can execute Java code, even from within the Command Window without the need to compile. For example, the traditional example:
>> import java.lang.*
>> System.out.println('Hello World')
Hello World
To perform socket communications, we utilise the Java Socket and Input/OutputStream classes to pass data around via TCP/IP sockets.

On the server side we use (unsurprisingly) a ServerSocket, which once a client has been accepted, provides a Socket around which we wrap a DataOutputStream to which we can write data.

On the client side we use a Socket to connect to the specified host and port which provides us an InputStream which we wrap in a DataInputStream to read data from.

The code for the example server and client is outlined below.

client.m
% CLIENT connect to a server and read a message
%
% Usage - message = client(host, port, number_of_retries)
function message = client(host, port, number_of_retries)

import java.net.Socket
import java.io.*

if (nargin <>
number_of_retries = 20; % set to -1 for infinite
end

retry = 0;
input_socket = [];
message = [];

while true

retry = retry + 1;
if ((number_of_retries > 0) && (retry > number_of_retries))
fprintf(1, 'Too many retries\n');
break;
end

try
fprintf(1, 'Retry %d connecting to %s:%d\n', ...
retry, host, port);

% throws if unable to connect
input_socket = Socket(host, port);

% get a buffered data input stream from the socket
input_stream = input_socket.getInputStream;
d_input_stream = DataInputStream(input_stream);

fprintf(1, 'Connected to server\n');

% read data from the socket - wait a short time first
pause(0.5);
bytes_available = input_stream.available;
fprintf(1, 'Reading %d bytes\n', bytes_available);

message = zeros(1, bytes_available, 'uint8');
for i = 1:bytes_available
message(i) = d_input_stream.readByte;
end

message = char(message);

% cleanup
input_socket.close;
break;

catch
if ~isempty(input_socket)
input_socket.close;
end

% pause before retrying
pause(1);
end
end
end

server.m
% SERVER Write a message over the specified port
%
% Usage - server(message, output_port, number_of_retries)
function server(message, output_port, number_of_retries)

import java.net.ServerSocket
import java.io.*

if (nargin <>
number_of_retries = 20; % set to -1 for infinite
end
retry = 0;

server_socket = [];
output_socket = [];

while true

retry = retry + 1;

try
if ((number_of_retries > 0) && (retry > number_of_retries))
fprintf(1, 'Too many retries\n');
break;
end

fprintf(1, ['Try %d waiting for client to connect to this ' ...
'host on port : %d\n'], retry, output_port);

% wait for 1 second for client to connect server socket
server_socket = ServerSocket(output_port);
server_socket.setSoTimeout(1000);

output_socket = server_socket.accept;

fprintf(1, 'Client connected\n');

output_stream = output_socket.getOutputStream;
d_output_stream = DataOutputStream(output_stream);

% output the data over the DataOutputStream
% Convert to stream of bytes
fprintf(1, 'Writing %d bytes\n', length(message))
d_output_stream.writeBytes(char(message));
d_output_stream.flush;

% clean up
server_socket.close;
output_socket.close;
break;

catch
if ~isempty(server_socket)
server_socket.close
end

if ~isempty(output_socket)
output_socket.close
end

% pause before retrying
pause(1);
end
end
end
Opening up two instances of Matlab:
% Instance 1
>> message = char(mod(1:1000, 255)+1);
>> server(message, 3000, 10)
Try 1 waiting for client to connect to this host on port : 3000
Try 2 waiting for client to connect to this host on port : 3000
Try 3 waiting for client to connect to this host on port : 3000
Try 4 waiting for client to connect to this host on port : 3000
Client connected
Writing 1000 bytes

% Instance 2 (simultaneously)
% NOTE: If the 'server' was runnning on a non local machine, substitute its IP address
% or host name here:
% data = client('10.61.1.200', 2666); % To connect to server at IP 10.61.1.200:2666
>> data = client('localhost', 3000)
Retry 1 connecting to localhost:3000
Retry 2 connecting to localhost:3000
Connected to server
Reading 1000 bytes

data =



 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~     

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~     

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~     

 !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~    
This code can be expanded to read/write arbitrary data types, and SHOULD be expanded to properly deal with errors (ie not getting all of the buffer on receive end), but it serves as a simple example of how to get communication between MATLAB and other applications / instances of MATLAB.

45 comments:

  1. Thanks, it is very easy to use and very useful.
    only one suggestion, in the example, although it is almost obvious, clarify you can put
    an specific IP (client('190.0.0.162',3000)) to connect to other PC instead of client('localhost',3000)
    Thanks again.

    ReplyDelete
  2. Ahhh yes, I assumed that would be obvious, for the purposes of the example (with 2 instances of Matlab running) only localhost will work.

    I'll update the example.

    Thanks

    ReplyDelete
  3. Hi Rodney

    I have Matlab 7.5.0
    I tried your example in two instances of matlab, but it is not working.
    here what I get in server side.

    >> message = char(mod(1:1000, 255)+1);
    >> server(message, 3000, 10)
    Try 1 waiting for client to connect to this host on port : 3000
    Try 2 waiting for client to connect to this host on port : 3000
    Try 3 waiting for client to connect to this host on port : 3000
    Try 4 waiting for client to connect to this host on port : 3000
    Try 5 waiting for client to connect to this host on port : 3000
    Try 6 waiting for client to connect to this host on port : 3000
    Try 7 waiting for client to connect to this host on port : 3000
    Try 8 waiting for client to connect to this host on port : 3000
    Try 9 waiting for client to connect to this host on port : 3000
    Try 10 waiting for client to connect to this host on port : 3000
    Too many retries

    and in client side I get also :
    >> data = client('localhost', 3000)
    Retry 1 connecting to localhost:3000
    Retry 2 connecting to localhost:3000
    Retry 3 connecting to localhost:3000
    Retry 4 connecting to localhost:3000
    Retry 5 connecting to localhost:3000
    Retry 6 connecting to localhost:3000
    Retry 7 connecting to localhost:3000
    Retry 8 connecting to localhost:3000
    Retry 9 connecting to localhost:3000
    Retry 10 connecting to localhost:3000
    Too many retries

    data =

    []

    P.S : I run the two command simultanously.

    Do you have any suggestion ? Thanks

    ReplyDelete
  4. Ok, firstly the obvious question:

    When you say you are running them simultaneously, does that also mean you are running the 2 instances on the same machine? If not, then the client will need to connect to the server machine (ie client('192.168.1.2', 3000))

    Other than that I would suggest checking any firewall services on your machine and make sure they are not blocking the incoming connections.

    Alternatively, you could test just the server alone by using telnet to connect. Start the MATLAB server method. Run telnet (Start->run(cmd), then type telnet localhost 3000) and verify you see the message appear.

    Any other dramas email me at rodney.thomson @ gmail.com

    ReplyDelete
  5. most helpful, thank you.

    ReplyDelete
  6. Hi Rodney

    would you mind see where the problem ,please ?

    I have Matlab 7.5.0

    I tryied examples using 2 machine
    and I put
    ie client('62.215.158.219', 3000))

    result :
    server

    >> message = char(mod(1:1000, 255)+1);
    >> server(message, 3000, 10)
    Try 1 waiting for client to connect to this host on port : 3000
    Try 2 waiting for client to connect to this host on port : 3000
    Try 3 waiting for client to connect to this host on port : 3000
    Try 4 waiting for client to connect to this host on port : 3000
    Try 5 waiting for client to connect to this host on port : 3000
    Try 6 waiting for client to connect to this host on port : 3000
    Try 7 waiting for client to connect to this host on port : 3000
    Try 8 waiting for client to connect to this host on port : 3000
    Try 9 waiting for client to connect to this host on port : 3000
    Try 10 waiting for client to connect to this host on port : 3000
    Too many retries

    client

    >> data = client('62.215.158.219', 3000)
    Retry 1 connecting to localhost:3000
    Retry 2 connecting to localhost:3000
    Retry 3 connecting to localhost:3000
    Retry 4 connecting to localhost:3000
    Retry 5 connecting to localhost:3000
    Retry 6 connecting to localhost:3000
    Retry 7 connecting to localhost:3000
    Retry 8 connecting to localhost:3000
    Retry 9 connecting to localhost:3000
    Retry 10 connecting to localhost:3000
    Too many retries

    data =

    []

    thanks

    ReplyDelete
  7. I can't see anything obvious as to why it would not be working in your scenario.

    A few things to check:

    - Firewall, ensure server ports are not being blocked
    - General connectivity, can you ping '62.215.158.219' from your client machine from within a Command Window (or terminal)

    Note that MATLAB has a manual proxy setup (if the machine you are attempting ot access is external to your network). It can be configured in File->Preferences->Web

    Hope that helps!

    ReplyDelete
  8. I'm not familiar with java and have been trying the Instrument Control Toolbox instead.

    I'm trying to create my own client SW to send data to a rapid prototyping machine.

    I can connect to the machine using both toolbox and your java method but i haven't been able to send the data that i've recorded in Wireshark.

    I have a few questions"
    1.Can your client script be modified to send messages? If so is it the same command as in the server script?

    2.is there a way to control the flags in the protocol? eg. ACK, SYN , Push?

    Thanks

    ReplyDelete
  9. Firstly, these files are just a simple EXAMPLE of TCP/IP socket comms in MATLAB. They are not always the best solution for every application. But they are a good starting point.

    1) Yes, the Java Socket interface (http://java.sun.com/j2se/1.4.2/docs/api/java/net/Socket.html) allows you to obtain an OutputStream (getOutputStream) from which you could apply the same techniques as in server.m to send data.

    2) As for manually manipulating the TCP/IP flags in the Java Sockets... errr pass! That a bit lower down then my current experience allows. Maybe try Google for those!

    Good Luck!

    Rod

    ReplyDelete
  10. thanks for your reply.

    what i was getting to about the TCPIP flags was that I can't get what the status of the packets are via the flags. eg. whether i received an ACK from the server so i can send the next packet.

    I can't find any documentations for the matlab instrument control and have already read through the JAVA tcpip tutorial and didn't find anything that would help me with this.

    Would you happen to know anything about this?

    Thanks

    ReplyDelete
  11. I've never personally dealt with the SYN/ACK stuff personally. I've always been sitting high and dry in the session layer with a nice TCP/IP Socket that hides all of that behavior.

    From initial glance, the default behavior of a Java Socket for writing is that it will be a blocking write, so if the Socket is unable to immediately send the data, it will wait as required.

    Sorry I'm not too much help with this!

    ReplyDelete
  12. Hi Rodney
    the connection done now
    the reason of failure :
    Firewall server ports was blocked
    and because I not run two command simultaneously.


    thank you very much

    ReplyDelete
  13. Hey Rodney,

    I find this link very useful for matlab users. I myself am using your code for communication between two matlab processes. I am trying to send a small file (around 600KB) from server end to the client end.
    Server flashes a message that it has sent all the data to the client but client script prints: "Reading 72 bytes"

    Can you suggest why client is not able to read all the data?

    Thanking You,
    Mayank

    ReplyDelete
  14. In client.m, it only attempts to read the data available on the underlying data stream (Socket in this case).

    There are a couple of ways you could attempt to ensure you read the entire contents of your file:

    1) sleep longer - Waiting until all of the data is sent and hopefully flushed

    2) Put a loop in client.m and keep attempting to read until the desired number of bytes has been read.

    Note: the specific example in client.m was really designed as a proof of concept and performs poorly with even relatively short messages. I'll post an update shortly which uses a compiled Java class to read data in a more efficient manner (but then becomes slightly more annoying having to cart a .class file around!)

    Rod

    ReplyDelete
  15. thanks rodney ,i tried your example and it's not working , i wanna know if i should have the same version of matlab in each instance ??
    and thank you another time

    ReplyDelete
  16. The versions of MATLAB should not be important so long as both are compatible with the inline Java calling (ie Release 14 onwards).

    ReplyDelete
  17. ok thank you rod ,for the moment it works but can i send images or another thing over this example ??
    and how ?? should i convert the image on "doublearray" or somthing like that ??
    thanks a lot rod

    ReplyDelete
  18. your comments mentioned that the input and output from the client and server respectively are buffered.
    I was reading
    http://java.sun.com/docs/books/tutorial/essential/io/buffers.html
    and I'm not very experience with java.
    How does the link above differ with yours?

    Thanks

    ReplyDelete
  19. hi,

    i having an issue where the 1st byte of what im sending is getting sent in it's own packet first then the next packet has the rest of the bytes.

    How do I solve this issue?

    thanks

    ReplyDelete
  20. for the moment it works but can i send images or another thing over this example ??Theoretically yes. Although it is not designed for this. If you had a double array:

    tmp = rand(1, 100);

    % store the data in the array as a series of chars
    tmp_byte = typecast(tmp, 'int8');

    % on server:
    server(char(tmp_byte), 3000, 10);

    % on client
    data_char = client('localhost', 3000);

    % convert back form bytes to doubles. Note you may need to convert from char to int8 first with 'int8(data_char)'
    data_double = typecast(data_char, 'double')

    i having an issue where the 1st byte of what im sending is getting sent in it's own packet first then the next packet has the rest of the bytes.I can suggest maybe modifying the client.m file to keep reading until the desired number of bytes has been read.

    One of these days i'll upload an improved method for reading in large amounts of data (unfortunately will need to resort to a Java .class file!)

    ReplyDelete
  21. thanks rod
    but i got problem with the length of the image ,this exemple dont support sending more than 8000 byte

    ReplyDelete
  22. Hi Rodney

    First of all I really want to thank you for this example: it's simple but very very useful!
    I've just a question for you: is there a way to make the server running in another thread, leaving the user free to type commands in the Matlab Command Window? I mean..a background server :)!

    Thank you for the help

    Gianluca

    ReplyDelete
  23. This comment has been removed by the author.

    ReplyDelete
  24. Hi Gianluca,

    Unfortunately MATLAB is inherently single threaded. That is why in my example I state "Open a second instance of MATLAB" to run the client.

    Some people have explored using Java Threading within MATLAB (http://www.osmanoglu.org/index.php/computing/4-computing/1-matlabjavamultitreading). This might give you some ideas (You may have to rewrite client/server in Java for this to work).

    ReplyDelete
  25. Hi Rodney,

    thank you for your answer. I also found the link in your answer, but I saw that they use Java thread separately from Matlab; what I'm trying to do is to make a "Matlab" server (maybe written using Java too) that permit to users, once it's started, to continue their work in Matlab. The problem is that the communication between Java and Matlab, using JMI, it's deprecated by Mathworks and no more supported, unlike the communication between Matlab and Java!
    So I hoped that there would be a way to use Java within a M-File to make that file (i.e., that function) multithread, but I think that's not possible..so I have just few choices:
    - use JMI hoping that it will work for at least the next two or three release;
    - use Matlab Engine and so use C/C++ instead of Java: the communication Matlab-C/C++ is suppported both ways.

    I don't know if I explained it well..I tried to summarize the problem at my best :)!

    Thanks again

    Gianluca

    ReplyDelete
  26. Hi Rodney
    How can I make connection between server and client in two different network
    I try to do it but it failure

    ReplyDelete
  27. Is it possible to read out the structure of the stream which was send?
    Are there any commands in matlab?
    And how can I put it into the example?

    Thanx for your Help und for your work

    ReplyDelete
  28. Hello I use you scripts in a GUI , and I want to know how could I make the server script to always listen for a connection. I tried a loop , I have a pushbutton and whe I press it it goes in a loop and waits for a connection but it blocks the matlab I can't do anything else , I also have a simulink model that I modifie some parameters in it whit the data that I receive from a connection but it blocks to , is there any way I can make the script to sleep for a time but only the GUI to sleep not Matlab, I've tried pause but it puts to sleep the GUI and the simulation . What should I do ?

    ReplyDelete
  29. I found this to be quite helpful, thank you!

    ReplyDelete
  30. Hello Rodney,

    First I would like to say that your communication file is brilliant!I am currently working on an undergraduate project that deals with port communication to MATLAB. One of our goals in the project is to take tracking information from Community Core Vision (a platform that inputs video stream (through a webcam) and outputs coordinate positions) and transport it into MATLAB. My group members and I know that the tracking information can be found in port 3333; we are finding difficulty, however, in transporting this information over to MATLAB. Then I stumbled upon your post and figured you were a person to contact about our problem (I found your email through the comments section). I have tried both of your m files(server.m and client.m) and I know they work (I keep on encountering errors, but I figure this is some human error in coding - I have a newer version of MATLAB as well). Will the m files you have written on this page help in our goal of transporting tracking information from port 3333 to MATLAB and reading out this data in MATLAB? Or do I require other things in these m files?

    ReplyDelete
  31. Mathlab also has its own tcp/ip functions:
    http://www.mathworks.com.au/help/toolbox/instrument/f16-54297.html

    ReplyDelete
  32. Hi, i want to send data via ethernet from matlab to my FPGA board and i have a question. Can i change this code to omit this part where we are connecting to the server and only send data without specyfing IP adres host etc. ?

    ReplyDelete
  33. @Anonymous on Jan 14 2013:
    Using TCP/IP? No, you must specify a host and port for a client to connect to.

    You MAY be able to do this with UDP, but I'll leave that to you to investigate.

    ReplyDelete
  34. @Rodney Thomson thanks for your reply.
    No, i dont need TCP/IP. On pc and on my fpga board there is no server, and shouldnt be. I have ethernet controler on board and i wonder if it works if i modify your matlab code to send only data via ethernet straight to board without setting IP etc.

    ReplyDelete
  35. @Anonymous:
    So you kind of want to use the Ethernet as a signal line for sending data to your FPGA? But without using TCP/IP or UDP/IP?

    That MIGHT be possible but you would have to get access to the ethernet at a low level (ie driver level), so as good as impossible.

    Sounds like your really just want a serial connection!

    Either that or just use TCP/IP.

    ReplyDelete
  36. Hi.. As simple as the working of the client program, Can it not send data to the server?

    I could not find a solution, and hoped it would be a piece of cake for you.

    Is it possible to send message to server, before waiting for a message.

    Tried to add d_output_stream from server code, and its not working.

    Suggestions please
    Thank you

    ReplyDelete
  37. @lakshman it is possible to modify the client to send days back to the server. Check back in the next few days and I'll try and upload an example.

    You have the right approach with the data output stream!

    ReplyDelete
  38. Hi Rodney Thomson,
    Thank you for very helpful codes

    I have strange problem when running code as follow:
    >> server(message, '3000', 10)
    Try 1 waiting for client to connect to this host on port : 51
    Try 48 waiting for client to connect to this host on port : 48
    Try 48 waiting for client to connect to this host on port : Try 2 waiting for client to connect to this host on port : 51
    Try 48 waiting for client to connect to this host on port : 48
    Try 48 waiting for client to connect to this host on port : Try 3 waiting for client to connect to this host on port : 51
    Try 48 waiting for client to connect to this host on port : 48
    Try 48 waiting for client to connect to this host on port : Try 4 waiting for client to connect to this host on port : 51
    Try 48 waiting for client to connect to this host on port : 48
    Try 48 waiting for client to connect to this host on port : Try 5 waiting for client to connect to this host on port : 51
    Try 48 waiting for client to connect to this host on port : 48
    Try 48 waiting for client to connect to this host on port : Try 6 waiting for client to connect to this host on port : 51
    Try 48 waiting for client to connect to this host on port : 48
    Try 48 waiting for client to connect to this host on port : Try 7 waiting for client to connect to this host on port : 51

    I dont know why this happens???
    So, would you give me any solutions for this,
    Thank you!

    ReplyDelete
  39. Port should be a number not a strong. Try:
    >> server(message, 3000, 10)

    ReplyDelete
  40. Hello Rodney,
    I read one of your comments: "IE it looks like you have bi-directional comms. You could setup one machine as server and another as client, then use the Java DataOutputStream/DataInputStream objects on both the client and server to both read and write data without re-establishing a connection each time"
    I try to modify your codes to make a server and a client connect all the time, and send/receive data bi-direction. But it seems connect only one time. So, would you tell me how can I make server/client to send and receive data all the time. Thank you!

    ReplyDelete
  41. Hi Rodney,

    I use your example code to communicate two instances of Matlab and it works perfect. I have a question, I need to work in a remote machine as if I were in the local machine, Is it possible to open a session in the remote machine as if I were in the session of the local machine with this type of communication?

    thanks in advance

    ReplyDelete
  42. @Anonymous (please put a name to the comments so I can address them!)

    You could in theory run remote commands using the eval() function and by sending commands. Maintaining a workspace of variables is more difficult, but again it is possible.

    What I would recommend you look at is using the MATLAB Mobile functionality as this can either run MATLAB 'in the cloud' or it can connect to a running instance of MATLAB on one of your lan/internet connected computers.

    http://www.mathworks.com.au/mobile/

    ReplyDelete
  43. I have tried to use your example, but when i try to connect to server , bring me back a error
    >> server(message, 3000, 10) [enter]
    ??? Error: File: server.m Line: 9 Column: 17
    Unexpected MATLAB operator.
    The line 9 is the code "if (nargin <>"

    I'm using matlab 7.11.0 R2010b.

    Tks for your support!

    ReplyDelete
  44. Carlos,

    I'm not sure if is a typo where you have written the error message, but line 9 should be:

    if (nargin < 3)

    and not

    if (nargin <>


    Please check that the contents are correct. Otherwise try downloading the file again from the Mathworks File Exchange

    ReplyDelete
  45. Hi Rodney,

    I'm more familiar with C++ than I am with Java. If I wanted to do this with an existing socket library written in C++, would I have to use MEX?

    Thanks,

    Allen

    ReplyDelete