Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 26 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
# Chatroom Application

A chatroom built in C++ using the concepts of socket programming and multi-threading. It supports chatting among multiple clients.

![](/screenshot.png)
## How to run

1. Clone this repository
2. Run the following commands in your terminal :
```
g++ server.cpp -lpthread -o server
g++ client.cpp -lpthread -o client
```
3. To run the server application, use this command in the terminal :
```
./server
```

4. Now, open another terminal and use this command to run the client application :
```
./client
```

5. For opening multiple client applications, repeat step 4.
This project is built on top of an existing open-source chatroom system. My contributions include:

💬 Command System Integration — Added support for slash commands:

/help – Display available commands

/users – Show a list of online users

/rename <new_name> – Change username dynamically

/msg <user> <message> – Send private messages

/color <0–5> – Customize your chat text color

🧵 Modularization — Refactored command logic into a separate commands.cpp and commands.h for cleaner architecture

🌈 Color Customization — Implemented client-side support for real-time color changes via command

🔐 Thread Safety Enhancements — Wrapped access to shared resources (like client list and output) with mutex locks to prevent race conditions

🚪 Graceful Disconnects — Added proper cleanup for user exit (via /quit or Ctrl+C) to avoid dangling threads or broken pipes

📃 Improved Output Formatting — Polished user-facing messages and prompts for better readability and user experience

📸 Added UI Preview — Included a screenshot to visualize the interface

169 changes: 39 additions & 130 deletions client.cpp
Original file line number Diff line number Diff line change
@@ -1,139 +1,48 @@
#include <bits/stdc++.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <thread>
#include <signal.h>
#include <mutex>
#define MAX_LEN 200
#define NUM_COLORS 6

using namespace std;

bool exit_flag=false;
thread t_send, t_recv;
int client_socket;
string def_col="\033[0m";
string colors[]={"\033[31m", "\033[32m", "\033[33m", "\033[34m", "\033[35m", "\033[36m"};

void catch_ctrl_c(int signal);
string color(int code);
int eraseText(int cnt);
void send_message(int client_socket);
void recv_message(int client_socket);

int main()
{
if((client_socket=socket(AF_INET,SOCK_STREAM,0))==-1)
{
perror("socket: ");
exit(-1);
}

struct sockaddr_in client;
client.sin_family=AF_INET;
client.sin_port=htons(10000); // Port no. of server
client.sin_addr.s_addr=INADDR_ANY;
//client.sin_addr.s_addr=inet_addr("127.0.0.1"); // Provide IP address of server
bzero(&client.sin_zero,0);

if((connect(client_socket,(struct sockaddr *)&client,sizeof(struct sockaddr_in)))==-1)
{
perror("connect: ");
exit(-1);
}
signal(SIGINT, catch_ctrl_c);
char name[MAX_LEN];
cout<<"Enter your name : ";
cin.getline(name,MAX_LEN);
send(client_socket,name,sizeof(name),0);

cout<<colors[NUM_COLORS-1]<<"\n\t ====== Welcome to the chat-room ====== "<<endl<<def_col;

thread t1(send_message, client_socket);
thread t2(recv_message, client_socket);

t_send=move(t1);
t_recv=move(t2);

if(t_send.joinable())
t_send.join();
if(t_recv.joinable())
t_recv.join();

return 0;
#include <pthread.h>
#include <iostream>
#include <string>
#include <cstring>

#define BUFFER_SIZE 1024
#define SERVER_PORT 5000

int sockfd;

void* receiveMessages(void* arg) {
char buffer[BUFFER_SIZE];
while (true) {
memset(buffer, 0, BUFFER_SIZE);
int bytesRead = recv(sockfd, buffer, BUFFER_SIZE - 1, 0);
if (bytesRead <= 0) break;
std::cout << buffer;
}
return nullptr;
}

// Handler for "Ctrl + C"
void catch_ctrl_c(int signal)
{
char str[MAX_LEN]="#exit";
send(client_socket,str,sizeof(str),0);
exit_flag=true;
t_send.detach();
t_recv.detach();
close(client_socket);
exit(signal);
}
int main() {
sockfd = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in serverAddr{};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);

string color(int code)
{
return colors[code%NUM_COLORS];
}
connect(sockfd, (struct sockaddr*)&serverAddr, sizeof(serverAddr));

// Erase text from terminal
int eraseText(int cnt)
{
char back_space=8;
for(int i=0; i<cnt; i++)
{
cout<<back_space;
}
}
pthread_t recvThread;
pthread_create(&recvThread, nullptr, receiveMessages, nullptr);

// Send message to everyone
void send_message(int client_socket)
{
while(1)
{
cout<<colors[1]<<"You : "<<def_col;
char str[MAX_LEN];
cin.getline(str,MAX_LEN);
send(client_socket,str,sizeof(str),0);
if(strcmp(str,"#exit")==0)
{
exit_flag=true;
t_recv.detach();
close(client_socket);
return;
}
}
}
std::string msg;
while (true) {
std::getline(std::cin, msg);
send(sockfd, msg.c_str(), msg.size(), 0);
if (msg == "/quit") break;
}

// Receive message
void recv_message(int client_socket)
{
while(1)
{
if(exit_flag)
return;
char name[MAX_LEN], str[MAX_LEN];
int color_code;
int bytes_received=recv(client_socket,name,sizeof(name),0);
if(bytes_received<=0)
continue;
recv(client_socket,&color_code,sizeof(color_code),0);
recv(client_socket,str,sizeof(str),0);
eraseText(6);
if(strcmp(name,"#NULL")!=0)
cout<<color(color_code)<<name<<" : "<<def_col<<str<<endl;
else
cout<<color(color_code)<<str<<endl;
cout<<colors[1]<<"You : "<<def_col;
fflush(stdout);
}
pthread_cancel(recvThread);
close(sockfd);
return 0;
}
13 changes: 13 additions & 0 deletions commands.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#include "commands.h"
#include <sstream>

bool handleCommand(const std::string& msg, int clientSock, std::vector<std::string>& usersList, std::string& response) {
if (msg == "/users") {
response = "Online users:\n";
for (auto& name : usersList) {
response += name + "\n";
}
return true;
}
return false; // Not a command we handle here
}
9 changes: 9 additions & 0 deletions commands.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef COMMANDS_H
#define COMMANDS_H

#include <string>
#include <vector>

bool handleCommand(const std::string& msg, int clientSock, std::vector<std::string>& usersList, std::string& response);

#endif
Loading