I want to send data from a client written in Matlab to a server written in C. When reading in the server, not all data is received in one read action and it is divided into two consecutive reads.
The Matlab code contains the code for a TCP server that receives some data, then does some processing and then writes (sends) the output of the processing over a TCP socket as a client to the server in C.
Here is the code for the client written in Matlab.
% A TCP server object defined for getting raw data and processing
% it. The object is called 'TCPServer'. It is not related to the
% problem.
% TCP client for sending the data to the C server
TCPClient = tcpip('192.168.1.2', 8080, 'NetworkRole', 'client');
set(TCPClient,'OutputBufferSize', 1464);
% 1464 is total number of bytes of the struct to be sent
% to the C server.
set(TCPClient,'Timeout', 10);
fopen(TCPClient);
while (1)
while(1) % Waits for incoming CSI data
nBytes = get(TCPServer,'BytesAvailable');
if nBytes >= bufferLen
disp('Data received');
break;
end
end
data = fread(TCPServer,nBytes,'uint8');
flushinput(TCPServer);
% Does some processing and generate 'spec' and 'doas'
% arrays to be sent to the C server
message = [typecast(spec, 'uint8') typecast(doas, 'uint8')];
fwrite(TCPClient, message);
end
Here is the code written in C for the server receiving the data from the client in Matlab.
#define SA struct sockaddr
struct doa_struct {
double spec[181], doa[2];
};
// Function that reads received data
void func(int sockfd)
{
struct doa_struct *doa_data;
unsigned char buff[1464];
int num_bytes;
// infinite loop receiving data
for (;;) {
bzero(buff, 1464);
// read the data from client and copy it in buffer
num_bytes = read(sockfd, buff, 1464);
// Get the buffer which contains the client contents
doa_data = (struct doa_struct *) buff;
printf("doa: %f\t%f\t%d\n", doa_data->doa[0], doa_data->doa[1], num_bytes);
}
}
// Driver function
int main()
{
int sockfd, connfd, len;
struct sockaddr_in servaddr, cli;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
printf("socket creation failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr, sizeof(servaddr));
// assign IP, PORT
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(8080);
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
printf("socket bind failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0) {
printf("Listen failed...\n");
exit(0);
}
else
printf("Server listening..\n");
len = sizeof(cli);
// Accept the data packet from client and verification
connfd = accept(sockfd, (SA*)&cli, &len);
if (connfd < 0) {
printf("server acccept failed...\n");
exit(0);
}
else
printf("server acccept the client...\n");
// Function for chatting between client and server
func(connfd);
// After chatting close the socket
close(sockfd);
}
I receive the following result on the server.
doa: 0.000000 0.000000 1408
doa: 0.000000 0.000000 56
Each line printed has three values. The first two are the received data that should not be zero. The last number is the number of bytes received by read()
function in the server. The sum of bytes received by the server in the two lines (two read()
operations) is 1464
which is the number of bytes sent by the client in one fwrite()
operation.
The correct output would be one line like the following:
doa: 25.000000 45.000000 1464
Two non-zero data values received by a transfer of 1464
bytes. I have also checked the client code. The client sends (writes) 1464
bytes by fwrite()
operation in Matlab.
It's completely normal for a read() call to only return some of the data you're expecting. This happens because at a low level, the network stack breaks the overall data stream up into multiple fixed-size packets for transmission over the wire. From the read(2) man page:
RETURN VALUE ... It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now (maybe because we were close to end-of-file, or because we are reading from a pipe, or from a terminal), or because read() was interrupted by a signal.
When receiving network data, you'll need to keep calling read() until you've received the expected number of bytes. For example, something like this (untested code):
void func(int sockfd)
{
struct doa_struct *doa_data;
int expected_bytes = 1464;
unsigned char buff[expected_bytes];
int num_bytes;
// Read a message
bzero(buff, 1464);
int bytes_read = 0;
while (bytes_read < expected_bytes) {
// read data into buff until we've read all the expected bytes
// NOTE: if the Matlab side sends a malformed message, this could
// hang in this loop forever...for real-world use, you'd need to
// account for those types of scenarios.
num_bytes = read(sockfd, buff + bytes_read, expected_bytes - bytes_read);
if (num_bytes <= 0) {
// handle error cases...
return;
}
bytes_read += num_bytes;
}
// Get the buffer which contains the client contents
doa_data = (struct doa_struct *) buff;
printf("doa: %f\t%f\t%d\n", doa_data->doa[0], doa_data->doa[1], num_bytes);
}
As for why your output is printing 0's instead of the expected values: it may be because of your printf format specifier. Your compiler may require "%lf" to print doubles, rather than "%f". Traditionally, the "%lf" was required for doubles, which are 64-bit values rather than the 32-bit float values. However, C99 and later compilers can blur this line -- see this related stack overflow question.