Skip to content

Instantly share code, notes, and snippets.

@ssrlive
Last active November 30, 2021 07:11
Show Gist options
  • Save ssrlive/d249599408d82f910756ea91cd83d292 to your computer and use it in GitHub Desktop.
Save ssrlive/d249599408d82f910756ea91cd83d292 to your computer and use it in GitHub Desktop.
Leaning AF_UNIX socket and pthread
// This sample program provides code for a client application that uses AF_UNIX
// address family
// https://www.ibm.com/docs/en/i/7.2?topic=uauaf-example-client-application-that-uses-af-unix-address-family
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include "thread-ctx.h"
void *thread_client(void *arguments) {
int sd = -1, rc, bytesReceived;
char buffer[BUFFER_LENGTH];
struct sockaddr_un serveraddr;
do {
sd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sd < 0) {
perror("socket() failed");
break;
}
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sun_family = AF_UNIX;
strcpy(serveraddr.sun_path, SERVER_PATH);
// strcpy(serveraddr.sun_path, argv[1]);
rc = connect(sd, (struct sockaddr *)&serveraddr, SUN_LEN(&serveraddr));
if (rc < 0) {
perror("connect() failed");
break;
}
memset(buffer, 'a', sizeof(buffer));
rc = send(sd, buffer, sizeof(buffer), 0);
if (rc < 0) {
perror("send() failed");
break;
}
/********************************************************************/
/* In this example we know that the server is going to respond with */
/* the same 250 bytes that we just sent. Since we know that 250 */
/* bytes are going to be sent back to us, we can use the */
/* SO_RCVLOWAT socket option and then issue a single recv() and */
/* retrieve all of the data. */
/* */
/* The use of SO_RCVLOWAT is already illustrated in the server */
/* side of this example, so we will do something different here. */
/* The 250 bytes of the data may arrive in separate packets, */
/* therefore we will issue recv() over and over again until all */
/* 250 bytes have arrived. */
/********************************************************************/
bytesReceived = 0;
while (bytesReceived < BUFFER_LENGTH) {
rc = recv(sd, &buffer[bytesReceived], BUFFER_LENGTH - bytesReceived, 0);
if (rc < 0) {
perror("recv() failed");
break;
} else if (rc == 0) {
printf("The server closed the connection\n");
break;
}
bytesReceived += rc;
}
} while (false);
if (sd != -1) {
close(sd);
}
return 0;
}
cmake_minimum_required(VERSION 3.4.1)
project(afunix)
add_executable( afsocket server.c client.c main.c )
target_link_libraries( afsocket pthread )
#include "thread-ctx.h"
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void *thread_server(void *arguments);
void *thread_client(void *arguments);
int main(int argc, char *const argv[]) {
size_t i;
pthread_t svr_thread;
pthread_t threads[MAX_COUNT] = {0};
int rc = 0;
struct main_thread_ctx *ctx =
(struct main_thread_ctx *)calloc(1, sizeof(*ctx));
// ctx->cond = PTHREAD_COND_INITIALIZER;
// ctx->mutex = PTHREAD_MUTEX_INITIALIZER;
rc = pthread_mutex_lock(&ctx->mutex);
pthread_create(&svr_thread, NULL, thread_server, ctx);
rc = pthread_cond_wait(&ctx->cond, &ctx->mutex);
rc = pthread_mutex_unlock(&ctx->mutex);
if (ctx->listened == false) {
pthread_join(svr_thread, NULL);
free(ctx);
printf("%s\n", "listen failed");
return -1;
}
for (i = 0; i < MAX_COUNT; i++) {
pthread_create(&threads[i], NULL, &thread_client, NULL);
}
pthread_join(svr_thread, NULL);
for (i = 0; i < MAX_COUNT; i++) {
pthread_join(threads[i], NULL);
}
sleep(1);
}
// This example program provides code for a server application that uses AF_UNIX
// address family
//
// https://www.ibm.com/docs/en/i/7.2?topic=uauaf-example-server-application-that-uses-af-unix-address-family
#include <pthread.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include "thread-ctx.h"
void *thread_incoming_socket(void *arguments);
void *thread_server(void *arguments) {
int sd = -1;
int rc, length;
int count = 0;
struct sockaddr_un serveraddr;
struct main_thread_ctx *ctx = (struct main_thread_ctx *)arguments;
do {
int index;
pthread_t threads[MAX_COUNT] = { 0 };
sd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sd < 0) {
perror("socket() failed");
break;
}
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sun_family = AF_UNIX;
strcpy(serveraddr.sun_path, SERVER_PATH);
rc = bind(sd, (struct sockaddr *)&serveraddr, SUN_LEN(&serveraddr));
if (rc < 0) {
perror("bind() failed");
break;
}
rc = listen(sd, 10);
if (rc < 0) {
perror("listen() failed");
break;
}
printf("Ready for client connect().\n");
ctx->listened = true;
rc = pthread_mutex_lock(&ctx->mutex);
rc = pthread_cond_signal(&ctx->cond);
rc = pthread_mutex_unlock(&ctx->mutex);
do {
int sd2 = -1;
pthread_t thread;
int *p = NULL;
if (++count > MAX_COUNT) {
break;
}
sd2 = accept(sd, NULL, NULL);
if (sd2 < 0) {
perror("accept() failed");
continue;
}
p = (int *)malloc(sizeof(*p));
if (p == NULL) {
close(sd2);
continue;
}
*p = sd2;
rc = pthread_create(&thread, NULL, &thread_incoming_socket, p);
threads[count - 1] = thread;
} while (true);
for (index = 0; index < MAX_COUNT; ++index) {
pthread_join(threads[index], NULL);
}
} while (false);
if (sd != -1) {
close(sd);
}
// Remove the UNIX path name from the file system
unlink(SERVER_PATH);
if (ctx->listened == false) {
rc = pthread_mutex_lock(&ctx->mutex);
rc = pthread_cond_signal(&ctx->cond);
rc = pthread_mutex_unlock(&ctx->mutex);
} else {
free(ctx);
}
return 0;
}
void *thread_incoming_socket(void *arguments) {
int rc, len;
int *p = (int *)arguments;
int sd2 = *p;
char buffer[BUFFER_LENGTH];
do {
/********************************************************************/
/* In this example we know that the client will send 250 bytes of */
/* data over. Knowing this, we can use the SO_RCVLOWAT socket */
/* option and specify that we don't want our recv() to wake up */
/* until all 250 bytes of data have arrived. */
/********************************************************************/
len = BUFFER_LENGTH;
rc = setsockopt(sd2, SOL_SOCKET, SO_RCVLOWAT, (char *)&len, sizeof(len));
if (rc < 0) {
perror("setsockopt(SO_RCVLOWAT) failed");
break;
}
rc = recv(sd2, buffer, sizeof(buffer), 0);
if (rc < 0) {
perror("recv() failed");
break;
}
printf("%d bytes of data were received\n", rc);
if (rc == 0 || rc < sizeof(buffer)) {
printf("The client closed the connection before all of the\n");
printf("data was sent\n");
break;
}
// Echo the data back to the client
rc = send(sd2, buffer, sizeof(buffer), 0);
if (rc < 0) {
perror("send() failed");
break;
}
} while (false);
close(sd2);
free(p);
}
#if !defined(__THREAD_CTX_H__)
#define __THREAD_CTX_H__
#include <pthread.h>
#include <stdbool.h>
struct main_thread_ctx {
pthread_cond_t cond;
pthread_mutex_t mutex;
bool listened;
};
#define MAX_COUNT 20
#define SERVER_PATH "/tmp/server"
#define BUFFER_LENGTH 250
#endif // __THREAD_CTX_H__
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment