(You might get eye-cancer today. So if you do not feel ready for this. Leave!)
This Server is trying to handle Clients communicating with each other. Because I was not willing to actually give every client a name, they are named by their socket's file descriptor. This is my first application which actually is able to communicate using the INET. It is also my first really multithreaded application.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdbool.h>
#define BUFLEN 255
#define MAX_CONNECTIONS 128
#define MAX_NAME_LENGTH 30
void delete_socket(int socketid);
void* job_read(void*);
void* job_write(void*);
//Global Variables
FILE* plogfile;
int socket_ids[MAX_CONNECTIONS];
bool endprogramm = false;
int open_cnncts = 0;
pthread_mutex_t socketids_changingMutex;
void error(const char* msg){
perror(msg);
exit(1);
}
int main(int argc, char* argv[]) {
printf("Server started...\n");
if(argc < 2){
fprintf(stderr, "You must provide a port number");
exit(EXIT_FAILURE);
}
if(argc == 3){
plogfile = fopen(argv[2], "w");
} else {
plogfile = fopen("logfile.txt", "w");
}
stderr = plogfile;
int sockfd;
uint16_t portnum;
//Create nmutthread
if(pthread_mutex_init(&socketids_changingMutex, NULL) < 0){
error("Could not initialize Mutex");
}
//Initialzing threads and create writethread
pthread_t writethread;
pthread_create(&writethread, NULL, job_write, NULL);
//Setup for connections
struct sockaddr_in serv_add;
struct sockaddr_in cli_adr;
socklen_t clilen;
clilen = sizeof(cli_adr);
bzero((char*)&serv_add, sizeof(struct sockaddr_in));
portnum = (uint16_t)atoi(argv[1]);
serv_add.sin_family = AF_INET;
serv_add.sin_addr.s_addr = INADDR_ANY;
serv_add.sin_port = htons(portnum);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
error("Error opening socket.");
}
if(bind(sockfd, (struct sockaddr*) (&serv_add), sizeof(serv_add)) < 0){
error("Binding failed.");
}
fprintf(plogfile,"Listening....");
listen(sockfd, MAX_CONNECTIONS);
for(open_cnncts = 0; (!endprogramm); /*mutex needs to be set*/ ){
socket_ids[open_cnncts] = accept(sockfd, (struct sockaddr*) &cli_adr, &clilen);
pthread_mutex_lock(&socketids_changingMutex);
fprintf(plogfile,"Client connected.\n");
pthread_t thread;
pthread_create(&thread , NULL, job_read, (void*)&socket_ids[open_cnncts]);
open_cnncts++;
pthread_mutex_unlock(&socketids_changingMutex);
}
endprogramm = true;
close(sockfd);
pthread_join(writethread, NULL);
pthread_mutex_destroy(&socketids_changingMutex);
return EXIT_SUCCESS;
}
void* job_read(void * p){
int* socketp = (int*)p;
int newsockfd = (*socketp);
ssize_t n; //Error catching variable
ssize_t m; //Error catching variable
char buffer[BUFLEN];
char name[MAX_NAME_LENGTH];
sprintf(name, "Client %d: ", newsockfd);
while(!endprogramm){
bzero(buffer, BUFLEN);
n = read(newsockfd, buffer, BUFLEN);
if(n<0){
printf("Buffer: %s", buffer);
error("Reading Failed");
}
if(n == 0){
delete_socket(newsockfd);
pthread_exit(NULL);
}
pthread_mutex_lock(&socketids_changingMutex);
for(int i = 0; i < open_cnncts; i++){
if(socket_ids[i] == newsockfd){
continue;
}
m = write(socket_ids[i], name, strlen(name));
n = write(socket_ids[i], buffer, strlen(buffer));
if(n < 0 | m < 0){
error("Writing failed");
}
}
pthread_mutex_unlock(&socketids_changingMutex);
printf("%s%s", name, buffer);
}
delete_socket(newsockfd);
pthread_exit( NULL );
}
void* job_write(void* args){
(void)args;
fprintf(plogfile, "Started writing thread...\n");
ssize_t n; //Error catching variable
ssize_t m; //Error catching variable
char buffer[BUFLEN];
char* name = "Server: \0";
while(!endprogramm) {
fgets(buffer, BUFLEN, stdin);
pthread_mutex_lock(&socketids_changingMutex);
for(int i = 0; i < open_cnncts; i++){
m = write(socket_ids[i], name, strlen(name));
n = write(socket_ids[i], buffer, strlen(buffer));
if(n < 0 | m < 0){
printf("Writing failed");
}
}
pthread_mutex_unlock(&socketids_changingMutex);
if(strcmp("Bye\n", buffer) == 0){
exit(EXIT_SUCCESS);
}
}
endprogramm = true;
pthread_exit( NULL );
}
void delete_socket(int socketid){
bool found = false;
for(int i = 0; i < open_cnncts; i++){
if(found){
socket_ids[i-1] = socket_ids[i];
}
if(socket_ids[i] == socketid){
close(socketid);
found = true;
}
}
if(found){
open_cnncts--;
}
}
Obviously, this code needs improvement, so just feel free to criticize everything criticizable. I would even more appreciate if you further comment about a better array-,thread-, and mutex handling.
Thank you!