Tutorial: Client/Server on the Raspberry Pi
--D. Thiebaut (talk) 16:52, 8 July 2013 (EDT)
A simple example to get started. The Raspberry Pi runs a server that waits for connection from a laptop, and expects integers from it. It multiplies each integer by 2 and sends it back. The laptop runs a client that initiates a connection, sends a bunch of positive integers that it gets back multiplied by two, and closes the connection by sending a -1. Sending a -2 causes the server to stop.
Hardware Setup
- The setup is that proposed in the excellent blog page at http://pihw.wordpress.com/guides/direct-network-connection/
- No need to try to copy what they already did very well, so simply follow their recommendations and connect your laptop to the Raspberry Pi using an ethernet cable.
Server/Client setup
- Here we take another good example from User Moorthy at RPI and adapt it slightly for our use.
Server code
/* A simple server in the internet domain using TCP.
myServer.c
D. Thiebaut
Adapted from http://www.cs.rpi.edu/~moorthy/Courses/os98/Pgms/socket.html
The port number used in 51717.
This code is compiled and run on the Raspberry as follows:
g++ -o myServer myServer.c
./myServer
The server waits for a connection request from a client.
The server assumes the client will send positive integers, which it sends back multiplied by 2.
If the server receives -1 it closes the socket with the client.
If the server receives -2, it exits.
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
void error( char *msg ) {
perror( msg );
exit(1);
}
int func( int a ) {
return 2 * a;
}
void sendData( int sockfd, int x ) {
int n;
char buffer[32];
sprintf( buffer, "%d\n", x );
if ( (n = write( sockfd, buffer, strlen(buffer) ) ) < 0 )
error( const_cast<char *>( "ERROR writing to socket") );
buffer[n] = '\0';
}
int getData( int sockfd ) {
char buffer[32];
int n;
if ( (n = read(sockfd,buffer,31) ) < 0 )
error( const_cast<char *>( "ERROR reading from socket") );
buffer[n] = '\0';
return atoi( buffer );
}
int main(int argc, char *argv[]) {
int sockfd, newsockfd, portno = 51717, clilen;
char buffer[256];
struct sockaddr_in serv_addr, cli_addr;
int n;
int data;
printf( "using port #%d\n", portno );
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error( const_cast<char *>("ERROR opening socket") );
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons( portno );
if (bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error( const_cast<char *>( "ERROR on binding" ) );
listen(sockfd,5);
clilen = sizeof(cli_addr);
//--- infinite wait on a connection ---
while ( 1 ) {
printf( "waiting for new client...\n" );
if ( ( newsockfd = accept( sockfd, (struct sockaddr *) &cli_addr, (socklen_t*) &clilen) ) < 0 )
error( const_cast<char *>("ERROR on accept") );
printf( "opened new communication with client\n" );
while ( 1 ) {
//---- wait for a number from client ---
data = getData( newsockfd );
printf( "got %d\n", data );
if ( data < 0 )
break;
data = func( data );
//--- send new data back ---
printf( "sending back %d\n", data );
sendData( newsockfd, data );
}
close( newsockfd );
//--- if -2 sent by client, we can quit ---
if ( data == -2 )
break;
}
return 0;
}
Client code
/* A simple client program to interact with the myServer.c program on the Raspberry.
myClient.c
D. Thiebaut
Adapted from http://www.cs.rpi.edu/~moorthy/Courses/os98/Pgms/socket.html
The port number used in 51717.
This code is compiled and run on the Macbook laptop is below:
g++ -o myClient myClient.c
./myClient
*/
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
void error(char *msg) {
perror(msg);
exit(0);
}
void sendData( int sockfd, int x ) {
int n;
char buffer[32];
sprintf( buffer, "%d\n", x );
if ( (n = write( sockfd, buffer, strlen(buffer) ) ) < 0 )
error( const_cast<char *>( "ERROR writing to socket") );
buffer[n] = '\0';
}
int getData( int sockfd ) {
char buffer[32];
int n;
if ( (n = read(sockfd,buffer,31) ) < 0 )
error( const_cast<char *>( "ERROR reading from socket") );
buffer[n] = '\0';
return atoi( buffer );
}
int main(int argc, char *argv[])
{
int sockfd, portno = 51717, n;
char serverIp[] = "169.254.0.2";
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
int data;
if (argc < 3) {
// error( const_cast<char *>( "usage myClient2 hostname port\n" ) );
printf( "contacting %s on port %d\n", serverIp, portno );
// exit(0);
}
if ( ( sockfd = socket(AF_INET, SOCK_STREAM, 0) ) < 0 )
error( const_cast<char *>( "ERROR opening socket") );
if ( ( server = gethostbyname( serverIp ) ) == NULL )
error( const_cast<char *>("ERROR, no such host\n") );
bzero( (char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy( (char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(portno);
if ( connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error( const_cast<char *>( "ERROR connecting") );
for ( n = 0; n < 10; n++ ) {
sendData( sockfd, n );
data = getData( sockfd );
printf("%d -> %d\n",n, data );
}
sendData( sockfd, -2 );
close( sockfd );
return 0;
}