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