Hello EZ.
This program uses datagram sockets to communicate. There is one server that gets all messages from the clients collects them in files and repeats the messages after the client has logged off. The files are named after the client's pid numbers.
The client is stopped with Crtl+d, which will log it off from the server and terminate. The server can be set in END modus by Ctrl+c. This won't stop it immediately. The server waits until all clients have logged off and terminates after that. In END modus the server will refuse the connection to new clients.
There is the code for the server:
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#define RUNNING 0
#define MESSAGE 1
#define END 2
#define BEGIN 3
void write_file(char fname[], char msg[]);
void display_file(char fname[]);
void sigfkt(int snr);
void register_sigfkt();
void init_address(struct sockaddr_un *srvadr);
void bind_address(struct sockaddr_un *srvadr, int sockd);
int init_socket();
int handle_client_request(char *eab, int sendcounter);
int modus = RUNNING;
int main(int argc, char **argv) {
int sockd;
int flags = 0;
int rc;
int sendcounter = 0;
socklen_t len;
struct sockaddr_un srvadr;
struct sockaddr_un cladr;
char eab[100];
register_sigfkt();
init_address(&srvadr);
sockd = init_socket();
bind_address(&srvadr, sockd);
printf("server started\n");
do {
len = sizeof(cladr);
memset(eab, '\0', sizeof(eab));
rc = recvfrom(sockd, eab, sizeof(eab), flags,
(struct sockaddr *)&cladr, &len);
if(rc < 0) {
perror("recvfrom");
} else {
sendcounter = handle_client_request(eab, sendcounter);
}
} while(sendcounter > 0 || modus != END);
printf("server stopped\n");
close(sockd);
unlink(srvadr.sun_path);
exit(0);
}
void write_file(char fname[], char msg[]) {
FILE *fp;
size_t rc;
size_t count = 1;
fp = fopen(fname, "a");
rc = fwrite(msg, strlen(msg), count, fp);
if(rc != count) {
perror("fwrite");
}
fclose(fp);
}
void display_file(char fname[]) {
FILE *fp;
char msg;
size_t count = 1;
fp = fopen(fname, "r");
while(fread(&msg, sizeof(char),count,fp) > 0) {
printf("%c", msg);
}
if(feof(fp)) {
puts("EOF\n");
} else {
perror("display_file");
}
fclose(fp);
}
void sigfkt(int snr) {
printf("sigfkt called\n");
if(snr == SIGINT) {
printf("terminating program ...\n\n");
modus = END;
}
}
void register_sigfkt() {
int rc;
struct sigaction disp;
disp.sa_handler = sigfkt;
disp.sa_flags = 0;
sigemptyset(&disp.sa_mask);
rc = sigaction(SIGINT, &disp, NULL);
if(rc != 0) {
perror("sigaction");
exit(1);
}
}
void init_address(struct sockaddr_un *srvadr) {
srvadr->sun_family = AF_UNIX;
strcpy(srvadr->sun_path, "sockdgram1");
unlink(srvadr->sun_path);
}
void bind_address(struct sockaddr_un *srvadr, int sockd) {
int rc = bind(sockd, (struct sockaddr *)srvadr, sizeof(*srvadr));
if(rc < 0) {
perror("bind");
exit(3);
}
}
int init_socket() {
int sockd = socket(AF_UNIX, SOCK_DGRAM, 0);
if(sockd < 0) {
perror("socket");
exit(2);
}
return sockd;
}
int handle_client_request(char *eab, int sendcounter) {
char fname[100];
pid_t pid;
int rc;
int control = eab[0];
unsigned int col_pos = strchr(eab,':') - eab;
strncpy(fname, &eab[1], col_pos-1);
fname[col_pos-1] = '\0';
pid = atoi(fname);
printf("client %s ", fname);
if(control == BEGIN && modus == END) {
//refuse clients in END modus
rc = kill(pid, SIGUSR1);
printf("refused\n");
if(rc < 0) {
perror("kill");
}
}
if(control == BEGIN && modus != END) {
printf("added\n");
sendcounter++;
printf("sendcounter = %d\n", sendcounter);
}
if(control == MESSAGE) {
write_file(fname, &eab[col_pos+1]);
printf("message: %s\n", &eab[col_pos+1]);
}
if(control == END) {
sendcounter--;
printf("checked out, show file\n");
display_file(fname);
printf("sendcounter = %d\n", sendcounter);
}
return sendcounter;
}
For the client:
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#define MESSAGE 1
#define END 2
#define BEGIN 3
void sigfkt(int signr);
void init_adr_info(struct sockaddr_un *srvadr);
int init_socket();
void create_socket_fname(struct sockaddr_un *cladr);
void send_start(struct sockaddr_un *srvadr, int sockd);
void send_end(struct sockaddr_un *srvadr, int sockd);
int send_msg(struct sockaddr_un *srvadr, int sockd, char *msg);
int main(int argc, char **argv){
int sockd;
char msg[100];
int rc;
struct sockaddr_un srvadr;
struct sockaddr_un cladr;
signal(SIGUSR1, sigfkt);
printf("started client %d\n", getpid());
init_adr_info(&srvadr);
sockd = init_socket();
create_socket_fname(&cladr);
send_start(&srvadr, sockd);
printf("message: \n");
while(fgets(msg, sizeof(msg), stdin) != NULL) {
rc = send_msg(&srvadr, sockd, msg);
if(rc == -1) {
break;
}
}
send_end(&srvadr, sockd);
close(sockd);
unlink(cladr.sun_path);
exit(0);
}
void sigfkt(int signr) {
printf("sender refused, terminating ...\n");
exit(3);
}
void init_adr_info(struct sockaddr_un *srvadr) {
srvadr->sun_family = AF_UNIX;
strcpy(srvadr->sun_path, "sockdgram1");
}
int init_socket() {
int sockd = socket(AF_UNIX, SOCK_DGRAM, 0);
if(sockd < 0) {
perror("socket");
exit(1);
}
return sockd;
}
void create_socket_fname(struct sockaddr_un *cladr) {
char clientname[50];
int rc;
strcpy(clientname, "sockXXXXXX");
rc = mkstemp(clientname);
if(rc == -1) {
perror("mkstemp");
exit(2);
}
strcpy(cladr->sun_path, clientname);
}
void send_start(struct sockaddr_un *srvadr, int sockd) {
char eab[100];
int flags = 0;
int rc;
sprintf(eab, "%c%d:", BEGIN, getpid());
rc = sendto(sockd, eab, strlen(eab), flags, (struct sockaddr*)srvadr,
sizeof(*srvadr));
if(rc < 0) {
perror("sendto start");
}
}
void send_end(struct sockaddr_un *srvadr, int sockd) {
char eab[100];
int flags = 0;
int rc;
sprintf(eab, "%c%d:", END, getpid());
rc = sendto(sockd, eab, strlen(eab), flags, (struct sockaddr*)srvadr,
sizeof(*srvadr));
if(rc < 0) {
perror("sendto end");
}
}
int send_msg(struct sockaddr_un *srvadr, int sockd, char *msg) {
char eab[100];
int flags = 0;
int rc;
sprintf(eab,"%c%d:%s", MESSAGE, getpid(), msg);
rc = sendto(sockd, eab, strlen(eab), flags,
(struct sockaddr*)srvadr, sizeof(*srvadr));
if(rc < 0) {
perror("sendto message");
}
if(rc == 0) {
printf("EOF");
return -1;
}
return 0;
}
The makefile:
all: server client
server: server.o
gcc -Wall -o server server.o
client: client.o
gcc -Wall -o client client.o
client.o: client.c
gcc -Wall -c client.c
server.o: server.c
gcc -Wall -c server.c
As usual I am open for suggestions for a better code. I have one question: Would you use #define or const for the modus constants (RUNNING, MESSAGE, END, BEGIN) and why?
Edit: Syntax highlighting removed.