Skip to content

Instantly share code, notes, and snippets.

@jweinst1
Last active June 2, 2024 04:57
Show Gist options
  • Save jweinst1/ab5b45be4adf6bac682800d95c4fc7e6 to your computer and use it in GitHub Desktop.
Save jweinst1/ab5b45be4adf6bac682800d95c4fc7e6 to your computer and use it in GitHub Desktop.
a polling and tcp based server and client in C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <poll.h>
static const char* local_host_ipv4 = "127.0.0.1";
static unsigned short port_nums[] = {12001, 12002};
// int inet_res = inet_aton(g_tcp_host, &(servaddr.sin_addr));
static int create_server_socket(unsigned short portno, const char* host, int blocking) {
struct sockaddr_in servaddr;
int server_fd = -1;
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
return server_fd;
}
if (!blocking) {
int flags = fcntl(server_fd, F_GETFL, 0);
if (fcntl(server_fd, F_SETFL, flags | O_NONBLOCK)) {
fprintf(stderr, "Cannot set non blocking on socket\n");
close(server_fd);
return -1;
}
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
int inet_res = inet_aton(host, &(servaddr.sin_addr));
if (inet_res == 0) {
fprintf(stderr, "Cannot convert host to ip!\n");
close(server_fd);
return -1;
}
servaddr.sin_port = htons(portno);
if ((bind(server_fd, (struct sockaddr*)&servaddr, sizeof(servaddr))) != 0) {
fprintf(stderr, "Cannot bind socket\n");
close(server_fd);
return -1;
}
if ((listen(server_fd, 10)) != 0) {
fprintf(stderr, "Cannot listen to socket\n");
close(server_fd);
return -1;
}
return server_fd;
}
static int create_client_socket(unsigned short portno, const char* host, int blocking) {
struct sockaddr_in servaddr;
int server_fd = -1;
server_fd = socket(AF_INET, SOCK_STREAM, 0);
if (server_fd == -1) {
return server_fd;
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
int inet_res = inet_aton(host, &(servaddr.sin_addr));
if (inet_res == 0) {
fprintf(stderr, "Cannot convert host to ip!\n");
close(server_fd);
return -1;
}
servaddr.sin_port = htons(portno);
errno=0;
while (connect(server_fd, (struct sockaddr*)&servaddr, sizeof(servaddr)) != 0) {
if (errno == EAGAIN || errno == EALREADY) {
errno = 0;
continue;
}
fprintf(stderr, "Failed to connect to host=%s, port=%u\n", host, portno);
perror("Error: ");
close(server_fd);
return -1;
}
if (!blocking) {
int flags = fcntl(server_fd, F_GETFL, 0);
if (fcntl(server_fd, F_SETFL, flags | O_NONBLOCK)) {
fprintf(stderr, "Cannot set non blocking on socket\n");
close(server_fd);
return -1;
}
}
return server_fd;
}
static int RET_GOOD = 0;
static int RET_BAD = 1;
static void* server_work(void* arg) {
uint64_t tid64;
int my_server;
int core_conn;
struct pollfd pollers[10];
nfds_t poller_count = 1;
pthread_threadid_np(NULL, &tid64);
unsigned short* my_port = arg;
printf("tid=%llu, my port is %u\n", tid64, *my_port);
if (*my_port % 2 == 0) {
// create client connection
do {
sleep(1);
printf("tid=%llu, currently connecting\n", tid64);
} while ((core_conn = create_client_socket(*my_port - 1, local_host_ipv4, 0)) == -1);
} else {
// create server connection
my_server = create_server_socket(*my_port, local_host_ipv4, 1);
if (my_server == -1) {
fprintf(stderr, "Thread id=%llu failed to create server socket!\n", tid64);
pthread_exit(&RET_BAD);
}
socklen_t clen = 0;
struct sockaddr_in cliaddr;
printf("tid=%llu, going to block on accept to see the other member\n", tid64);
int result = accept(my_server, (struct sockaddr*)&cliaddr, &clen);
int rflags = fcntl(result, F_GETFL, 0);
if (fcntl(result, F_SETFL, rflags | O_NONBLOCK)) {
fprintf(stderr, "tid=%llu Cannot set non blocking on socket\n", tid64);
close(result);
abort();
}
core_conn = result;
}
pollers[0].fd = core_conn;
pollers[0].events = POLLIN;
while(1) {
unsigned char byte_to_send = 0;
if (*my_port % 2 == 0) {
byte_to_send = 44;
} else {
byte_to_send = 22;
}
errno = 0;
write(pollers[0].fd, &byte_to_send, sizeof(byte_to_send));
if (errno == EAGAIN || errno == EWOULDBLOCK) {
fprintf(stderr, "tid=%llu, got blocked on a write!", tid64);
}
errno = 0;
int ready = poll(pollers, poller_count, -1);
if (ready == -1) {
fprintf(stderr, "Got bad return from poll, errno=%d\n", errno);
//pthread_exit(&RET_BAD);
} else if (ready == 0) {
printf("tid=%llu, Timeout passed on poll!\n", tid64);
} else {
if (pollers[0].revents & POLLIN) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
printf("tid=%llu, Nothing to read!\n", tid64);
} else {
printf("tid=%llu, Got in event via poll!", tid64);
unsigned char byte = 0;
read(pollers[0].fd, &byte, sizeof(byte));
printf("tid=%llu, got byte %u\n", tid64, byte);
}
}
}
}
if (*my_port % 2 != 0) {
close(my_server);
}
close(core_conn);
pthread_exit(&RET_GOOD);
}
int main(int argc, char const *argv[])
{
//int* foo = NULL;
//pthread_join(id, (void**)&foo);
signal(SIGPIPE, SIG_IGN);
pthread_t id1;
pthread_t id2;
int s1 = pthread_create(&id1, NULL, &server_work, port_nums);
int s2 = pthread_create(&id2, NULL, &server_work, port_nums + 1);
if(s1 || s2) {
fprintf(stderr, "failed to create thread!!!\n");
abort();
}
int* exit_stat = NULL;
pthread_join(id1, (void**)&exit_stat);
pthread_join(id2, (void**)&exit_stat);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment