Simple IPC by Socket on Linux
Communicate between process on the same host or different hosts.
- On the same host: Use INET socket or UNIX socket
- On different hosts: Use UNIX socket
Head File [sock.h]
#ifndef __SOCK_H
#define __SOCK_H
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <stddef.h>
#include <string.h>
/* ===== API for simple INET/UNIX socket ===== */
/*
Create a server
If port is valid, create an INET server.
Otherwise, create an UNIX server.
Return serverfd for OK, negetive value for ERR
Example:
[INET Server]
int serverfd;
if ((serverfd = sock_server(2333, NULL, 5)) < 0)
{
prinf("Error: fail to create server\n");
}
[UNIX Server]
int serverfd;
if ((serverfd = sock_server(-1, "test.sock", 5)) < 0)
{
prinf("Error: fail to create server\n");
}
*/
int sock_server(int port, const char *sockfile, int max_connection);
/*
Accept a client and create a session
Return sessionfd for OK, negetive value for ERR
Example:
int sessionfd;
if ((sessionfd = sock_accept(serverfd)) < 0)
{
prinf("Error: fail to accept client\n");
}
*/
int sock_accept(int serverfd);
/*
Create a client connected to a server
If host and port are valid, create an INET client.
Otherwise, create an UNIX client.
Return clientfd for OK, negetive value for ERR
Example:
[INET Client]
int clientfd;
if ((clientfd = sock_client("127.0.0.1", 2333, NULL)) < 0)
{
printf("Error: fail to create client\n");
}
[UNIX Client]
int clientfd;
if ((clientfd = sock_client(NULL, -1, "test.sock")) < 0)
{
prinf("Error: fail to create client\n");
}
*/
int sock_client(const char *host, int port, const char *sockfile);
/*
Close a server/client/session
Example:
close(clientfd);
close(sessionfd);
close(serverfd);
*/
void sock_close(int fd);
/*
Send message
Return message length sent for OK, negetive value for ERR
Example:
if ((sock_send(clientfd, msg, msg_len) < 0)
{
printf("Error: fail to send message\n");
}
*/
ssize_t sock_send(int sockfd, const void *buf, size_t len);
/*
Receive message
Return message length received for OK, negetive value for ERR
Example:
if ((msg_len = sock_recv(sessionfd, buf, MAX_LEN) < 0)
{
printf("Error: fail to receive message\n");
}
*/
ssize_t sock_recv(int sockfd, void *buf, size_t len);
/*
Sock Example:
[Sever]
int serverfd;
int sessionfd;
char buf[512];
int len;
if ((serverfd = sock_server(-1, "test.sock", 5)) < 0)
{
exit(-1);
}
if ((sessionfd = sock_accept(serverfd)) < 0)
{
exit(-2);
}
if ((len = sock_recv(sessionfd, buf, 512)) > 0)
{
buf[len] = 0;
printf("Recv: %s\n", buf);
}
sock_close(sessionfd);
sock_close(serverfd);
[Client]
int clientfd;
char buf[512];
int len;
if ((clientfd = sock_client(NULL, -1, "test.sock")) < 0)
{
exit(-1);
}
sprintf(buf, "Hello world");
len = strlen(buf);
if ((len = sock_send(clientfd, buf, len)) > 0)
{
printf("Send: %s\n", buf);
}
sock_close(clientfd);
*/
#endif
Source File [sock.c]
#include "sock.h"
int sock_server(int port, const char *sockfile, int max_connection)
{
int domain;
struct sockaddr *addr;
int serverfd;
struct sockaddr_in in;
struct sockaddr_un un;
int len;
/* Parse socket type */
if (port >= 0)
{
domain = AF_INET;
addr = (struct sockaddr *) ∈
memset(&in, 0, sizeof(in));
in.sin_family = AF_INET;
in.sin_addr.s_addr = htonl(INADDR_ANY);
in.sin_port = htons(port);
len = sizeof(in);
}
else if (sockfile != NULL)
{
domain = AF_UNIX;
addr = (struct sockaddr *) &un;
/* Remove old file if it exists */
unlink(sockfile);
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, sockfile);
len = offsetof(struct sockaddr_un, sun_path) + strlen(sockfile);
}
else
{
return -1;
}
/* Create socket */
if ((serverfd = socket(domain, SOCK_STREAM, 0)) < 0)
{
return -2;
}
/* Bind socket */
if (bind(serverfd, addr, len) < 0)
{
close(serverfd);
return -3;
}
/* Start listening */
if (listen(serverfd, max_connection) < 0)
{
close(serverfd);
return -4;
}
return serverfd;
}
int sock_accept(int serverfd)
{
int sessionfd;
/* Accept client connection */
if ((sessionfd = accept(serverfd, NULL, NULL)) < 0)
{
return -1;
}
return sessionfd;
}
int sock_client(const char *host, int port, const char *sockfile)
{
int domain;
int clientfd;
struct sockaddr *addr;
struct sockaddr_in in;
struct hostent *h;
struct sockaddr_un un;
int len;
/* Parse socket type */
if (host != NULL && port > 0)
{
domain = AF_INET;
addr = (struct sockaddr *) ∈
memset(&in, 0, sizeof(in));
in.sin_family = AF_INET;
/* Read ip */
if (inet_pton(AF_INET, host, &in.sin_addr) <= 0)
{
/* Failed to read ip from host, try gethostbyname */
if ((h = gethostbyname(host)) == NULL)
{
return -1;
}
memcpy(&in.sin_addr.s_addr, h->h_addr, 4);
}
in.sin_port = htons(port);
len = sizeof(in);
}
else if (sockfile != NULL)
{
domain = AF_UNIX;
addr = (struct sockaddr *) &un;
memset(&un, 0, sizeof(un));
un.sun_family = AF_UNIX;
strcpy(un.sun_path, sockfile);
len = offsetof(struct sockaddr_un, sun_path) + strlen(sockfile);
}
/* Create socket */
if ((clientfd = socket(domain, SOCK_STREAM, 0)) < 0 )
{
return -2;
}
/* Connect server */
if (connect(clientfd, addr, len) < 0)
{
close(clientfd);
return -3;
}
return clientfd;
}
void sock_close(int fd)
{
close(fd);
}
ssize_t sock_send(int sockfd, const void *buf, size_t len)
{
return send(sockfd, buf, len, 0);
}
ssize_t sock_recv(int sockfd, void *buf, size_t len)
{
return recv(sockfd, buf, len, 0);
}
Demo File [ever.c]
#include "sock.h"
#include <unistd.h>
static char *SOCK_NAME = "test.sock";
void start_daemon(int port)
{
int serverfd;
int sessionfd;
char buf[512];
int len;
printf("Start\n");
if ((serverfd = sock_server(port, SOCK_NAME, 5)) < 0)
{
printf("Error[%5d]: fail to create server\n", serverfd);
return;
}
new_session:
if ((sessionfd = sock_accept(serverfd)) < 0 )
{
printf("Error[%5d]: fail to accept client\n", sessionfd);
return;
}
dup2(sessionfd, STDOUT_FILENO);
if ((len = sock_recv(sessionfd, buf, 512)) > 0)
{
buf[len] = 0;
printf("Recv: %s\n", buf);
}
sock_close(sessionfd);
if (strncmp(buf, "stop", 4))
goto new_session;
sock_close(serverfd);
printf("Stop\n");
}
void send_cmd(char *cmd, const char *host, int port)
{
int clientfd;
int len;
char buf[512];
if ((clientfd = sock_client(host, port, SOCK_NAME)) < 0)
{
printf("Error[%5d]: fail to create client\n", clientfd);
return;
}
len = strlen(cmd);
len = sock_send(clientfd, cmd, len);
printf("Send %s [len: %d]\n", cmd, len);
if ((len = sock_recv(clientfd, buf, 512)) > 0)
{
buf[len] = 0;
printf("Recv: %s\n", buf);
}
sock_close(clientfd);
}
void stop_daemon(const char *host, int port)
{
send_cmd("stop", host, port);
}
int main(int argc, char *argv[])
{
char *host = "127.0.0.1";
int port = 6666;
if (argc < 2)
{
printf("usage: %s <cmd> [ip port]", argv[0]);
return -1;
}
if (!strcmp(argv[1], "start"))
{
if (argc > 2)
port = atoi(argv[2]);
start_daemon(port);
}
else if (!strcmp(argv[1], "stop"))
{
if (argc > 3)
{
host = argv[2];
port = atoi(argv[3]);
}
stop_daemon(host, port);
}
else
{
if (argc > 3)
{
host = argv[2];
port = atoi(argv[3]);
}
send_cmd(argv[1], host, port);
}
return 0;
}
Build & Run
Build [Makefile]
CC := gcc
TARGETS := ever
all: $(TARGETS)
ever: ever.o sock.o
$(CC) -o $@ $^
%.o: %.c
$(CC) -c -o $@ $<
clean:
-rm $(TARGETS)
-rm *.o
Run
Run server on one terminal
$ ./ever start
Run client on another terminal
On the same host:
$ ./ever message
On a different host:
$ ./ever message xxx.xxx.xxx.xxx 6666