Last active
November 30, 2021 07:11
-
-
Save ssrlive/d249599408d82f910756ea91cd83d292 to your computer and use it in GitHub Desktop.
Leaning AF_UNIX socket and pthread
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cmake_minimum_required(VERSION 3.4.1) | |
project(afunix) | |
add_executable( afsocket server.c client.c main.c ) | |
target_link_libraries( afsocket pthread ) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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