Makistos
11/7/2014 - 1:02 PM

A simple Linux socket example. #c #socket #linux

A simple Linux socket example. #c #socket #linux

#ifndef __SOCKET_H__
#define __SOCKET_H__

#include <sys/socket.h>
#include <stdbool.h>

#define SOCKET_NAME "/tmp/testsocket"

#define MAX_BUFFER 10000

typedef void* (*PTHREAD_FN)(void*);
/* Function prototypes */
bool socket_exists();
int socket_create(char *sock_name);
int socket_connect(char *name);
void socket_send(int sock, char *msg, size_t msg_len);
#endif
#include <sys/stat.h>
#include <sys/un.h>
#include <string.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>

#include "socket.h"

bool socket_exists(const char *sock_name)
{
	struct stat sts;
	bool retval = true;

	if (stat(sock_name, &sts) == -1 && errno == ENOENT) {
		return false;
	}

	return retval;
}

int socket_create(char *sock_name)
{
	int retval;
	size_t size;
	struct sockaddr_un name;
	int flags;
	int result;

	printf("Creating local socket.\n");

	/* Create socket */
	if ((retval = socket(PF_LOCAL, SOCK_SEQPACKET, 0))< 0) {
		printf("Socket creation failed.\n");
		return -1;
	}

	name.sun_family = AF_LOCAL;
	strncpy(name.sun_path, sock_name, sizeof(name.sun_path));
	size = (offsetof (struct sockaddr_un, sun_path)
	        + strlen (name.sun_path) + 1);

	if (bind(retval, (struct sockaddr*) &name, (socklen_t)size) < 0) {
		printf("Failed to bind socket.\n");
		return -1;
	}

	if (listen(retval, 1) == -1) {
		printf("Socket listen failed: %d.\n", errno);
		return -1;
	}

	flags = fcntl(retval, F_GETFL);
	result = fcntl(retval, F_SETFL, flags & ~O_NONBLOCK);
	result = chmod(sock_name, S_IRWXU | S_IRWXG | S_IRWXO);
	return retval;
}

int socket_connect(char *name)
{
	int retval;
	struct sockaddr_un daemon;
	int size;
	int flags;
	int result;
	printf("Connecting to local socket.\n");

	if ((retval = socket(PF_LOCAL, SOCK_SEQPACKET, 0)) == -1) {
		printf("Failed to create socket.\n");
		return 0;
	}

	daemon.sun_family = AF_LOCAL;
	strncpy(daemon.sun_path, name, sizeof(daemon.sun_path));
	size = (int)(offsetof (struct sockaddr_un, sun_path)
	        + strlen (daemon.sun_path) + 1);

	if (connect(retval, (struct sockaddr*) &daemon, (socklen_t)size) == -1) {
		printf("Failed to connect to socket %s: %d.\n", name, errno);
		return -1;
	}

	flags = fcntl(retval, F_GETFL);
	result = fcntl(retval, F_SETFL, flags & ~O_NONBLOCK);
	printf("Connected to socket %d.\n", retval);
	return retval;
}

void socket_send(int sock, char *msg, size_t msg_len)
{
	printf("Sending message %s to %d of length %d.\n", msg, sock, (int)msg_len);

	if (send(sock, msg, msg_len, 0) == -1) {
		printf("Failed to send message to socket %d: %d. Length: %d. Contents: %s", sock, errno, (int)msg_len, msg);
		return;
	}

}
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <stdbool.h>

#include "socket.h"

static void socket_receive(void* arg)
{
	ssize_t received;
	char buffer[MAX_BUFFER];
	int sock = *((int*)arg);
	int err_flag = 0;

	while (true) {
		received = recv(sock, buffer, MAX_BUFFER, 0);

		if (received != -1 && received != 0) {
			printf("Message received from socket %d: %s\n", sock, buffer);
			/* Send the same message back */
			socket_send(sock, buffer, strlen(buffer));
		} else if (received < 0) {
			if (err_flag == 0) {
				printf( "Error receiving data from client %d: %d.\n", sock, errno);
				err_flag++;
			}
		} else {
			/* Socket was closed */
			printf("Client socket %d closed.\n", sock);
			break;
		}
	}
}

static void socket_wait_client(int sock)
{
	int status;
	pthread_t listener_task;
	int new_sock;
	printf("Waiting for client.\n");

	while (true) {
		/* Wait for client to connect. */
		if ((new_sock = (accept(sock, (struct sockaddr*)NULL, NULL))) < 0) {
			printf("Failed to accept client connection.\n");
			return;
		} else {
			printf("Client %d connected to server.\n", new_sock);
		}

		/* Create listener thread */
		printf("Starting server receive process for %d.\n", new_sock);

		if ((status = pthread_create(&listener_task, NULL, (PTHREAD_FN)socket_receive, (void*)&new_sock)) < 0) {
			printf("Failed to start socket listener task.\n");
		}
	}
}


static void socket_start()
{
	int sock;

	printf("Starting socket server.\n");

	if (socket_exists(SOCKET_NAME) == true) {
		/* Delete existing socket fd */
		(void)unlink(SOCKET_NAME);
	}

	sock = socket_create(SOCKET_NAME);
	socket_wait_client(sock);
}


int main(void)
{
	socket_start();
	return 0;
}
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>

#include "socket.h"

static char g_buffer[MAX_BUFFER];

static void socket_receive(int sock)
{
	ssize_t received;
	char *buffer;
	int err_flag = 0;

	buffer = (char*)malloc(MAX_BUFFER);
	if (buffer == NULL)
		return;

	received = recv(sock, buffer, MAX_BUFFER, 0);

	if (received != -1 && received != 0) {
		printf("Message received from socket %d. Length %d. %s\n", sock, (int)received, buffer);
	} else if (received < 0) {
		if (err_flag == 0) {
			/* Sometimes an error can cause this value to be returned
			 * indefinitely, let's print this just once in any case. */
			printf( "Error receiving data from client %d: %d.\n", sock, errno);
			err_flag++;
		}
	} else {
		/* Socket was closed */
		printf("Client socket %d closed.\n", sock);
	}

	free (buffer);
}

static void socket_start()
{
	int sock;

	printf("Connecting to server.\n");
	sock = socket_connect(SOCKET_NAME);
	socket_send(sock, g_buffer, strlen(g_buffer));
	socket_receive(sock);
}


int main(int argc, char **argv)
{
	char default_string[] = "TEST STRING";

	switch (argc) {
		case 1:
			strcpy(g_buffer, default_string);
			break;
		case 2:
			strcpy(g_buffer, argv[1]);
			break;
	}

	socket_start();

	return 0;
}

Socket example

Compile with

gcc client.c socket.c -o client && gcc server.c socket.c -o server -lpthread

Then start server and run client with or without a parameter. If you run these in different terminals it's easier to follow what happens.

Server should print something like

Starting socket server.
Creating local socket.
Waiting for client.
Client 4 connected to server.
Starting server receive process for 4.
Message received from socket 4: barf
Sending message barf to 4 of length 4.
Client socket 4 closed.

And client should print

Connecting to server.
Connecting to local socket.
Connected to socket 3.
Sending message barf to 3 of length 4.
Message received from socket 3. Length 4. barf