|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <sys/socket.h> |
|
#include <sys/types.h> |
|
#include <netinet/in.h> |
|
#include <arpa/inet.h> |
|
#include <errno.h> |
|
#include <string.h> |
|
#include <pthread.h> |
|
#include <stdbool.h> |
|
|
|
#define MAX_CLIENTS 20 |
|
#define MAX_DATA 1024 |
|
|
|
static unsigned int count = 0; |
|
static int client_id = 0; |
|
|
|
char user_list[MAX_DATA]; |
|
|
|
typedef struct { |
|
struct sockaddr_in addr; //client address |
|
int sockfd; //file descriptor |
|
int index; //mark client by a integer number |
|
char name[20]; //name of the client |
|
} client_info; |
|
client_info *client_list[MAX_CLIENTS]; |
|
|
|
void *client_connection_handler(void *socket); |
|
void add_client(client_info *new_client); //Connect/Add a new client to server |
|
void remove_client(int target); //Remove a client |
|
|
|
void message_all(char *message_to_send); //Send message to all clients |
|
void broadcast(char *message_to_send, |
|
int index); //Send message to all but self |
|
void echo(const char *message_to_send, |
|
int sending_sockfd); //Send message to incoming sender |
|
|
|
void new_message(char *message); //Send new message |
|
void list_all_user(int sockfd); |
|
|
|
int main(int argc, char **argv) { |
|
int sock, new; |
|
struct sockaddr_in server, client; |
|
int sockaddr_len = sizeof(struct sockaddr_in); |
|
pthread_t new_thread; |
|
int data_len; |
|
char data[MAX_DATA]; |
|
|
|
sock = socket(AF_INET, SOCK_STREAM, 0); |
|
if (sock == -1) { |
|
printf("the value of the socekt is%d\n ", sock); |
|
perror("socket: "); |
|
exit(-1); |
|
} |
|
|
|
printf("Socket is successfully created\n"); |
|
bzero((char *)&server, sizeof(server)); |
|
server.sin_family = AF_INET; |
|
server.sin_port = htons(23333); |
|
server.sin_addr.s_addr = INADDR_ANY; |
|
|
|
if (bind(sock, (struct sockaddr *)&server, sockaddr_len) < 0) { |
|
perror("Bind failed"); |
|
exit(1); |
|
} |
|
printf("Binding was successfull\n"); |
|
|
|
if (listen(sock, MAX_CLIENTS) < 0) { |
|
perror("Listen failed"); |
|
exit(1); |
|
} |
|
|
|
while (1) { |
|
new = accept(sock, (struct sockaddr *)&client, &sockaddr_len); |
|
|
|
if (new < 0) { |
|
perror("Accept failed "); |
|
exit(1); |
|
} |
|
printf("New client connected from port %d\n", ntohs(client.sin_port)); |
|
|
|
client_info *new_client = (client_info *)malloc(sizeof(client_info)); |
|
new_client->addr = client; |
|
new_client->sockfd = new; |
|
new_client->index = client_id++; |
|
sprintf(new_client->name, "Client %d", new_client->index); |
|
add_client(new_client); |
|
|
|
if (pthread_create(&new_thread, NULL, &client_connection_handler, |
|
(void *)new_client) < 0) { |
|
perror("Thread failed to create"); |
|
} |
|
} |
|
return 0; |
|
} |
|
|
|
//Handle connection from clients |
|
void *client_connection_handler(void *socket) { |
|
if (count >= MAX_CLIENTS) { |
|
printf("MAX number of clients reached\n"); |
|
return; |
|
} |
|
|
|
count++; |
|
|
|
char mes_in[MAX_DATA]; |
|
char mes_out[MAX_DATA]; |
|
|
|
int data_size; |
|
client_info *client = (client_info *)socket; |
|
int client_index = client->index; |
|
|
|
printf("Data received. "); |
|
strcpy(mes_out, client->name); |
|
strcat(mes_out, " joined.\n"); |
|
broadcast(mes_out, client_index); //if new client registered, broadcast to all clients |
|
data_size = 1; |
|
while (data_size) { |
|
data_size = recv(client->sockfd, mes_in, MAX_DATA, 0); |
|
mes_in[data_size] = '\0'; |
|
mes_out[0] = '\0'; |
|
printf("Message: %s\n", mes_in); |
|
if (data_size) { |
|
new_message(mes_in); |
|
|
|
if (!strlen(mes_in)) { |
|
continue; |
|
} |
|
|
|
if (mes_in[0] == '/') { |
|
char *command, *param; |
|
command = strtok(mes_in, " "); |
|
printf("User command received: %s\n", command); |
|
if (strcmp(command, "/QUIT") == 0) { |
|
break; |
|
|
|
|
|
} else if (!strcmp(command, "/TEST")) { |
|
echo("\nConnected!.\r\n", client->sockfd); |
|
|
|
|
|
} else if (!strcmp(command,"/SHOW")) { |
|
sprintf(mes_out, "\nTotal number of client(s): %d\r\n", count); |
|
echo(mes_out, client->sockfd); |
|
list_all_user(client->sockfd); |
|
|
|
|
|
} else { |
|
echo("Unknown command\r\n", client->sockfd); |
|
} |
|
} else { |
|
sprintf(mes_out, "[%s] %s\r\n", client->name, mes_in); |
|
message_all(mes_in); |
|
} |
|
} |
|
} |
|
|
|
printf("Client disconnected\n"); |
|
|
|
close(client->sockfd); |
|
sprintf(mes_out, "Index %d %s has quit\r\n", client->index, client->name); |
|
message_all(mes_out); |
|
|
|
//Delete client from queue and yeild thread |
|
remove_client(client->index); |
|
free(client); |
|
count--; |
|
pthread_detach(pthread_self()); |
|
} |
|
|
|
void add_client(client_info *new_client) { |
|
int i; |
|
printf("Creating new client.\n"); |
|
for (i = 0; i < MAX_CLIENTS; ++i) { |
|
if (!client_list[i]) { |
|
client_list[i] = new_client; |
|
printf("New client created: Client %d\n", i); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
void remove_client(int target) { |
|
int i; |
|
printf("Removing client.\n"); |
|
for (i = 0; i < MAX_CLIENTS; ++i) { |
|
if (client_list[i] && client_list[i]->index == target) { |
|
client_list[i] = NULL; |
|
printf("Client %d has been removed\n", i); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
void message_all(char *message_to_send) { |
|
int i; |
|
for (i = 0; i < MAX_CLIENTS; i++) { |
|
if (client_list[i]) { |
|
write(client_list[i]->sockfd, message_to_send, strlen(message_to_send)); |
|
} |
|
} |
|
} |
|
|
|
void broadcast(char *message_to_send, int index) { |
|
int i; |
|
for (i = 0; i < MAX_CLIENTS; i++) { |
|
if (client_list[i] && client_list[i]->index != index) { |
|
write(client_list[i]->sockfd, message_to_send, strlen(message_to_send)); |
|
} |
|
} |
|
} |
|
|
|
void echo(const char *message_to_send, int sending_sockfd) { |
|
write(sending_sockfd, message_to_send, strlen(message_to_send)); |
|
} |
|
|
|
void new_message(char *message) { |
|
while (*message != '\0') { |
|
if (*message == '\r' || *message == '\n') { |
|
*message = '\0'; |
|
} |
|
message++; |
|
} |
|
} |
|
|
|
void list_all_user(int sockfd) { |
|
int i; |
|
for (i = 0; i < MAX_CLIENTS; i++) { |
|
if (client_list[i]) { |
|
sprintf(user_list, "Index: %d, Name: %s\r\n", client_list[i]->index, |
|
client_list[i]->name); |
|
echo(user_list, sockfd); |
|
} |
|
} |
|
} |