Skip to content

Instantly share code, notes, and snippets.

@Makistos
Last active September 5, 2018 08:10
Show Gist options
  • Save Makistos/efe060414cda119bbbb0 to your computer and use it in GitHub Desktop.
Save Makistos/efe060414cda119bbbb0 to your computer and use it in GitHub Desktop.
A simple Linux socket example. #c #socket #linux

Socket example

Compile with

gcc -Wall -pedantic -Wextra -Werror client.c socket.c -o client && gcc server.c socket.c -o server -lpthread

(Should produce no warnings.)

This simple socket example demonstrates how to run a server and multiple clients. Client can be started with or without a parameter. If a parameter is used it is sent to the server after which client exits. If no parameter is supplied client enters a loop asking for messages to send from the user. typing "quit" quits the client. First client started acts as a control channel, typing "quit" into it also quits server process. This is because that server listener is created from the main thread and exiting it will also exit the main thread ending the program.

Output should look something like shown below.

Single client with command-line command

Server:

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

Client:

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

Multi-client example

Server:

Starting socket server.
Creating local socket.
Waiting for client.
Client 4 connected to server.
Creating local socket.
Waiting for client.
Client 6 connected to server.
Creating local socket.
Waiting for client.
Message received from socket 4: foobar
Sending message foobar to 4 of length 6.
Message received from socket 6: barbar
Sending message barbar to 6 of length 6.
Message received from socket 6: quit
Sending message quit to 6 of length 4.
Received quit from 6
Message received from socket 4: quit
Sending message quit to 4 of length 4.
Received quit from 4

Client 1:

Connecting to server.
Connecting to local socket.
Connected to socket 3.
Message: foobar
Sending message foobar to 3 of length 6.
Message received from socket 3. Length 6. foobar
Message: quit
Sending message quit to 3 of length 4.
Message received from socket 3. Length 4. quit

Client 2:

Connecting to server.
Connecting to local socket.
Connected to socket 3.
Message: barbar
Sending message barbar to 3 of length 6.
Message received from socket 3. Length 6. barbar
Message: quit
Sending message quit to 3 of length 4.
Message received from socket 3. Length 4. quit
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <stdbool.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) {
buffer[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;
bool quit = false;
printf("Connecting to server.\n");
if (strlen(g_buffer) != 0) {
/* If command was received from command line, just send that
* and quit */
quit = true;
}
sock = socket_connect(SOCKET_NAME);
do {
if (strlen(g_buffer) == 0) {
printf("Message: ");
scanf("%s", g_buffer);
if (!strcmp(g_buffer, "quit"))
quit = true;
}
socket_send(sock, g_buffer, (strlen(g_buffer) < MAX_BUFFER ? strlen(g_buffer): MAX_BUFFER));
socket_receive(sock);
memset(g_buffer, 0x0, MAX_BUFFER);
} while (!quit);
}
int main(int argc, char **argv)
{
g_buffer[0] = '\0';
switch (argc) {
case 1:
break;
case 2:
strncpy(g_buffer, argv[1], MAX_BUFFER);
break;
}
socket_start();
return 0;
}
CC = gcc
CCFLAGS = -Wall -Wextra -pedantic -Werror
LIBS = -lpthread
all: server client
SERVER_SRC = server.c socket.c
CLIENT_SRC = client.c socket.c
server: ${SERVER_SRC}
${CC} ${CCFLAGS} ${SERVER_SRC} -o server ${LIBS}
client: ${CLIENT_SRC}
${CC} ${CCFLAGS} ${CLIENT_SRC} -o client
#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_start();
static void socket_receive(int sock)
{
ssize_t received;
char buffer[MAX_BUFFER];
bool quit = false;
int err_flag = 0;
while (!quit) {
memset(buffer, 0x0, MAX_BUFFER);
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));
if (!strncmp(buffer, "quit", strlen(buffer))) {
printf("Received quit from %d\n", sock);
quit = true;
}
} 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);
quit = true;
break;
}
}
}
static void socket_wait_client(int sock)
{
pthread_t new_client;
int new_sock;
printf("Waiting for client.\n");
/* 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);
}
/* Start new wait thread for next client */
if ((pthread_create(&new_client, NULL, (PTHREAD_FN)socket_start, NULL)) < 0) {
printf("Failed to start next wait_client thread.");
}
socket_receive(new_sock);
}
static void socket_start()
{
int sock;
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)
{
printf("Starting socket server.\n");
socket_start();
return 0;
}
#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;
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);
(void)fcntl(retval, F_SETFL, flags & ~O_NONBLOCK);
(void)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;
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);
(void)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;
}
}
#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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment