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.

44 comments:

Anonymous said...

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.

Rodney Thomson said...

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

Anonymous said...

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

Rodney Thomson said...

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

Allison said...

most helpful, thank you.

Anonymous said...

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

Rodney Thomson said...

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!

Anonymous said...

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

Rodney Thomson said...

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

Anonymous said...

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

Rodney Thomson said...

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!

Anonymous said...

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

Anonymous said...

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

Rodney Thomson said...

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

Anonymous said...

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

Rodney Thomson said...

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

Anonymous said...

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

Anonymous said...

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

Anonymous said...

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

Rodney Thomson said...

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!)

Anonymous said...

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

Gianluca M. said...

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

Gianluca M. said...
This comment has been removed by the author.
Rodney Thomson said...

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).

Gianluca M. said...

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

Anonymous said...

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

Henniger said...

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

catalin_benea said...

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 ?

Zachary said...

I found this to be quite helpful, thank you!

ab said...

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?

Anonymous said...

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

Anonymous said...

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. ?

Rodney Thomson said...

@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.

Anonymous said...

@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.

Rodney Thomson said...

@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.

lakshman said...

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

Rodney Thomson said...

@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!

Anonymous said...

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!

Rodney Thomson said...

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

Anonymous said...

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!

Anonymous said...

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

Rodney Thomson said...

@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/

GOUVÊA, Carlos said...

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!

Rodney Thomson said...

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