Socket Tutorial

From ElphelWiki
Revision as of 01:56, 29 November 2008 by OneArtPlease (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Socket Communication Tutorial with Elphel Cameras

This Tutorial will guide through creating a client - server communication framework example between a host computer and an Elphel camera using C.

This will only work under Linux!

Installing the Axis Compiler

The camera runs a kind of embedded Linux so we cannot use the normal (gcc) compiler for running our code on the camera but need a compiler for a specific target running environment.

Axis has a very comprehensive guide on installing and using their compiler.

Downloading and installing the compiler: http://developer.axis.com/wiki/doku.php?id=axis:compiler_install

This compile can take quite some time so make yourself a cup of tea or two.

The second guide on the Axis wiki is a short compile walkthrough: http://developer.axis.com/wiki/doku.php?id=axis:compiling_for_cris_howto, which we will cover later for our server source as well anyway.

Creating the Client Application

When referring to a client here I mean the computer which we will use to send requests to the camera.

Lets create a new file called client.c and paste the following code into it (thanks to the original creator):

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>

#define BUFFSIZE 32
void Die(char *mess) { perror(mess); exit(1); }


int main(int argc, char *argv[]) {
	int sock;
	struct sockaddr_in echoserver;
	char buffer[BUFFSIZE];
	unsigned int echolen;
	int received = 0;

	if (argc != 4) {
		fprintf(stderr, "USAGE: TCPecho <server_ip> <word> <port>\n");
		exit(1);
	}
	/* Create the TCP socket */
	if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) 	
	{
		Die("Failed to create socket");
	}

	/* Construct the server sockaddr_in structure */
	memset(&echoserver, 0, sizeof(echoserver));       /* Clear struct */
	echoserver.sin_family = AF_INET;                  /* Internet/IP */
	echoserver.sin_addr.s_addr = inet_addr(argv[1]);  /* IP address */
	echoserver.sin_port = htons(atoi(argv[3]));       /* server port */
	/* Establish connection */
	if (connect(sock, (struct sockaddr *) &echoserver, sizeof(echoserver)) < 0) {
		Die("Failed to connect with server");
	}

	/* Send the word to the server */
	echolen = strlen(argv[2]);
	if (send(sock, argv[2], echolen, 0) != echolen) {
		Die("Mismatch in number of sent bytes");
	}
	/* Receive the word back from the server */
	fprintf(stdout, "Received: ");
	while (received < echolen) {
		int bytes = 0;
		if ((bytes = recv(sock, buffer, BUFFSIZE-1, 0)) < 1) {
			Die("Failed to receive bytes from server");
		}
		received += bytes;
		buffer[bytes] = '\0';        /* Assure null terminated string */
		fprintf(stdout, buffer);
	}

	fprintf(stdout, "\n");
	close(sock);
	exit(0);
}

The next step requires a working compile environment. Make sure you have "build-essentials" package installed or otherwise get it with (typing in terminal):

sudo apt-get install build-essentials

Now we compile this the good old linux way by opening a terminal.

gcc client.c -o client.o
gcc is the compiler
client.c is the source file we just created
-o client.o defines where we we want the compiled output

If everything goes well there should now be a file called client.o in the same directory as the source file. If it did not work the compiler should have supplied one or more error messages.

To test the application we just compile now type:

./client.o

You should get an output like this:

USAGE: TCPecho <server_ip> <word> <port>

More about the usage later.


Creating the Server Application

Create another file called server.c and paste the following source code into it:

#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>

#define MAXPENDING 5    /* Max connection requests */
#define BUFFSIZE 32
void Die(char *mess) { perror(mess); exit(1); }


void HandleClient(int sock) {
	char buffer[BUFFSIZE];
	int received = -1;
	/* Receive message */
	if ((received = recv(sock, buffer, BUFFSIZE, 0)) < 0) {
		Die("Failed to receive initial bytes from client");
	}
	/* Send bytes and check for more incoming data in loop */
	while (received > 0) {
		/* Send back received data */
		if (send(sock, buffer, received, 0) != received) {
			Die("Failed to send bytes to client");
		}
		/* Check for more data */
		if ((received = recv(sock, buffer, BUFFSIZE, 0)) < 0) {
			Die("Failed to receive additional bytes from client");
		}
	}
	close(sock);
}

int main(int argc, char *argv[]) {
	int serversock, clientsock;
	struct sockaddr_in echoserver, echoclient;

	if (argc != 2) {
		fprintf(stderr, "USAGE: echoserver <port>\n");
		exit(1);
	}
	/* Create the TCP socket */
	if ((serversock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
		Die("Failed to create socket");
	}
	/* Construct the server sockaddr_in structure */
	memset(&echoserver, 0, sizeof(echoserver));       /* Clear struct */
	echoserver.sin_family = AF_INET;                  /* Internet/IP */
	echoserver.sin_addr.s_addr = htonl(INADDR_ANY);   /* Incoming addr */
	echoserver.sin_port = htons(atoi(argv[1]));       /* server port */

	/* Bind the server socket */
	if (bind(serversock, (struct sockaddr *) &echoserver, sizeof(echoserver)) < 0) {
		Die("Failed to bind the server socket");
	}
	/* Listen on the server socket */
	if (listen(serversock, MAXPENDING) < 0) {
		Die("Failed to listen on server socket");
	}
	/* Run until cancelled */
	while (1) {
		unsigned int clientlen = sizeof(echoclient);
		/* Wait for client connection */
		if ((clientsock = accept(serversock, (struct sockaddr *) &echoclient, &clientlen)) < 0) 
		{
			Die("Failed to accept client connection");
		}
		fprintf(stdout, "Client connected: %s\n", inet_ntoa(echoclient.sin_addr));
		HandleClient(clientsock);
	}
}