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;
}
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