//server side code
#include<stdlib.h>
#include<unistd.h>
#include<sys/socket.h>
#include<stdio.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<errno.h>
#include<string.h>
#include<pthread.h>
#include<sys/types.h>
#include<signal.h>
#define MAX_CLIENTS 100
#define BUFFER_SZ 2048
#define NAME_LEN 32
static int cli_count = 0;
static int uid = 10;
//client structure
typedef struct
{
struct sockaddr_in address;
int sockfd;
int uid;
char name[NAME_LEN];
} client_t;
client_t *clients[MAX_CLIENTS];
pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
void str_overwrite_stdout()
{
printf("\r %s",">");
fflush(stdout);
}
void str_trim_lf(char* arr, int length)
{
for(int i=0; i<length; i++)
{
if(arr[i] == '\n')
{
arr[i] = '\0';
break;
}
}
}
void queue_add(client_t *cl)
{
pthread_mutex_lock(&clients_mutex);
for(int i=0; i<MAX_CLIENTS; i++)
{
if(!clients[i])
{
clients[i] = cl;
break;
}
}
pthread_mutex_unlock(&clients_mutex);
}
void queue_remove(int uid)
{
pthread_mutex_lock(&clients_mutex);
for(int i=0; i<MAX_CLIENTS; i++)
{
if(clients[i])
{
if(clients[i] -> uid == uid)
{
clients[i] = NULL;
break;
}
}
}
pthread_mutex_unlock(&clients_mutex);
}
void print_ip_addr(struct sockaddr_in addr)
{
printf("%d.%d.%d.%d",
addr.sin_addr.s_addr & 0xff,
(addr.sin_addr.s_addr & 0xff00) >> 8,
(addr.sin_addr.s_addr & 0xff0000) >> 16,
(addr.sin_addr.s_addr & 0xff000000) >> 24);
}
void send_message(char *s, int uid)
{
pthread_mutex_lock(&clients_mutex);
for(int i=0; i<MAX_CLIENTS; i++)
{
if(clients[i])
{
if(clients[i] -> uid != uid)
{
if(write(clients[i]->sockfd, s, strlen(s)) < 0)
{
printf("ERROR: write to descriptor failed\n");
break;
}
}
}
}
pthread_mutex_unlock(&clients_mutex);
}
void *handle_client(void *arg)
{
char buffer[BUFFER_SZ];
char name[NAME_LEN];
int leave_flag = 0;
cli_count++;
client_t *cli = (client_t*)arg;
//name
if(recv(cli->sockfd, name, NAME_LEN, 0) <= 0 || strlen(name) < 2 || strlen(name) >= NAME_LEN - 1)
{
printf("Enter the name: \n");
leave_flag = 1;
}
else
{
strcpy(cli->name, name);
printf(buffer, "%s has joined\n", cli->name);
printf("%s", buffer);
send_message(buffer, cli->uid);
}
memset(handle_client, BUFFER_SZ, 8*sizeof(name)); //8*sizeof(name)
while(1)
{
if(leave_flag)
{
break;
}
int receive = recv(cli->sockfd, buffer, BUFFER_SZ, 0);
if (receive > 0)
{
if(strlen(buffer) > 0)
{
send_message(buffer, cli->uid);
str_trim_lf(buffer, strlen(buffer));
printf("%s\n ", buffer);
}
}
else if (receive == 0 || strcmp(buffer, "exit") == 0)
{
sprintf(buffer, "%s has left\n", cli->name); //sprintf instead of printf
printf("%s", buffer);
send_message(buffer, cli->uid);
leave_flag = 1;
}
else
{
printf("ERROR: -1\n");
leave_flag = 1;
}
//memset
memset(handle_client, BUFFER_SZ, 8*sizeof(name));
}
close(cli->sockfd);
queue_remove(cli->uid);
free(cli);
cli_count--;
pthread_detach(pthread_self());
return NULL;
}
int main(int argc, char **argv)
{
if (argc != 2)
{
printf("usuage: %s <port>\n", argv[0]);
return EXIT_FAILURE;
}
char *ip = "127.0.0.1";
int port = atoi(argv[1]);
int option = 1;
int listenfd = 0, connfd = 0;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
pthread_t ptid;
//socket settings
listenfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr(ip);
serv_addr.sin_port = htons(4444);
//signals
signal(SIGPIPE, SIG_IGN);
if(setsockopt(listenfd, SOL_SOCKET, (SO_REUSEPORT | SO_REUSEADDR), (char*)&option, sizeof(option)) < 0)
{
printf("ERROR: setsockopt\n");
return EXIT_FAILURE;
}
//bind
if (bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)
{
printf("ERROR: bind\n");
return EXIT_FAILURE;
}
//listen
if(listen(listenfd, 10) < 0)
{
printf("ERROR: listen\n");
return EXIT_FAILURE;
}
printf(" ----- WELCOME TO THE CHAT SERVER -----\n");
while(1)
{
socklen_t clilen = sizeof(cli_addr);
connfd = accept(listenfd, (struct sockaddr*)&cli_addr, &clilen);
//check for max client
if((cli_count + 1) == MAX_CLIENTS)
{
printf("Maximum Clients Connected. Connection rejected!");
print_ip_addr(cli_addr);
close(connfd);
continue;
}
//client settings
client_t *cli = (client_t *)malloc(sizeof(client_t));
cli->address = cli_addr;
cli->sockfd = connfd;
cli->uid = uid++;
//add client to queue
queue_add(cli);
pthread_create(&ptid, NULL, &handle_client, (void*)cli);
//reduce CPU usuage
sleep(1);
}
return EXIT_SUCCESS;
}
//client-side
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<sys/types.h>
#include<string.h>
#include<pthread.h>
#include<signal.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#define MAX_CLIENTS 100
#define BUFFER_SZ 2048
#define NAME_LEN 32
volatile sig_atomic_t flag = 0;
int sockfd = 0;
char name[NAME_LEN];
void str_overwrite_stdout()
{
printf("\r%s", ">");
fflush(stdout);
}
void str_trim_lf(char* arr, int length)
{
for(int i=0; i<length; i++)
{
if(arr[i] == '\n')
{
arr[i] = '\0';
break;
}
}
}
void catch_ctrl_c_and_exit ()
{
flag = 1;
}
void recv_msg_handler()
{
char message[BUFFER_SZ] = {};
while(1)
{
int receive = recv(sockfd, message, BUFFER_SZ, 0);
if(receive > 0)
{
printf("%s", message);
str_overwrite_stdout();
}
else if(receive == 0)
{
break;
}
memset(message, BUFFER_SZ, 1); // memeset
}
}
void send_msg_handler()
{
char buffer[BUFFER_SZ] = {};
char message[BUFFER_SZ + NAME_LEN] = {};
while(1)
{
str_overwrite_stdout();
fgets(buffer, BUFFER_SZ, stdin);
str_trim_lf(buffer, BUFFER_SZ);
if(strcmp(buffer, "exit") == 0)
{
break;
}
else
{
sprintf(message, "%s: %s\n", name, buffer);
send(sockfd, message, strlen(message), 0);
}
memset(buffer, BUFFER_SZ, 1); //memset
memset(message, BUFFER_SZ + NAME_LEN, 1); //memset
}
catch_ctrl_c_and_exit(2);
}
int main(int argc, char **argv)
{
if(argc != 2)
{
printf("Usuage: %s <port>\n", argv[0]);
return EXIT_FAILURE;
}
char *ip = "127.0.0.1";
int port = atoi(argv[1]);
signal(SIGINT, catch_ctrl_c_and_exit);
printf("Enter your name: \n");
fgets(name, NAME_LEN, stdin);
str_trim_lf(name, strlen(name));
if(strlen(name) > NAME_LEN - 1 || strlen(name) < 2)
{
printf("Enter the name correctly");
return EXIT_FAILURE;
}
struct sockaddr_in toserver;
//socket settings
sockfd = socket(AF_INET, SOCK_STREAM, 0);
toserver.sin_family = AF_INET;
toserver.sin_addr.s_addr = inet_addr(ip);
toserver.sin_port = htons(4444);
//connect client to server
int err = connect(sockfd, (struct sockaddr*)&toserver, sizeof(toserver));
if (err == -1)
{
printf("ERROR: connect\n");
return EXIT_FAILURE;
}
//send the name
send(sockfd, name, NAME_LEN, 0);
printf("--- WELCOME TO CHAT SERVER ---\n");
pthread_t send_msg_thread;
if(pthread_create(&send_msg_thread, NULL, (void*)send_msg_handler, NULL) != 0)
{
printf("ERROR: pthread\n");
return EXIT_FAILURE;
}
pthread_t recv_msg_thread;
if(pthread_create(&recv_msg_thread, NULL, (void*)recv_msg_handler, NULL) != 0)
{
printf("ERROR: pthread\n");
return EXIT_FAILURE;
}
while(1)
{
if(flag)
{
printf("\n BYE \n");
break;
}
}
close(sockfd);
return EXIT_SUCCESS;
}
Я пытался запустить код, но каждый раз, когда я получаю ошибку сегментации после приветствия на сервере чата, не мог бы кто-нибудь из вас помочь мне с этим. Для запуска я использую G CC.
Код фактически пытается передать сообщение, полученное от клиента, и отправить его всем другим клиентам, присоединившимся к серверу.