c++ : terminal chat : simple multi thread chat for single client

terminal chat : simple multi thread chat for single client, uses c++ socket programming and  multi threading, threads used to read and write simultaneously on a single socket, there is much more better ways such as select(), but as an experimental program its good to do that with threads.

compile server side with:
g++ chatserver.cpp -lpthread -o chatserver
compile client side with:
g++ chatclient.cpp -lpthread -o chatclient

Usage:

on server side: ./chatserver port

example: ./chatserver 2017

on client side:

./chatclient server_ip server_port

example:

./chatclient 192.168.10.1 2017

the source code and binaries are available on github

chatserver.cpp

 

#define _BSD_SOURCE
#include <arpa/inet.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
#include <fstream>
#include <strings.h>
#include <stdlib.h>
#include <string>
#include <pthread.h>
using namespace std;

void *rcv(void *);
void *snd(void *);

static int client_sock;
static int server_sock;
static int read_size;
static string clsource;

int main(int argc, char* argv[])
{
int pid, port;
socklen_t len;
struct sockaddr_in server_address, client_address;

pthread_t proc_thread[3];

if (argc < 2)
{
cerr << "Syntax : ./chatserver <port>" << endl;
return 0;
}

port = atoi(argv[1]);

if((port > 65535) || (port < 1024))
{
cerr << "Please enter a port number between 1024 - 65535" << endl;
return 0;
}

//create socket
server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if(server_sock < 0)
{
cerr << "Cannot open socket" << endl;
return 0;
}

bzero((char*) &server_address, sizeof(server_address));

server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(port);

//bind socket
if(bind(server_sock, (struct sockaddr *)&server_address, sizeof(server_address)) < 0)
{
cerr << "Cannot bind to port " << port << endl;
return 0;
}

//listen on binded socket
listen(server_sock, 5);


int thread_num = 0;

while (thread_num <3 )
{

socklen_t len = sizeof(client_address);


cout << "Listening On Port " << port << endl;

// Accept Incoming Connections
client_sock = accept(server_sock, (struct sockaddr *)&client_address, &len);

if (client_sock < 0)
{
cerr << "Cannot accept connection" << endl;
return 0;
}
else
{
clsource=inet_ntoa(client_address.sin_addr);
cout << "Accepted Connection From:" << clsource << endl;
}

pthread_create(&proc_thread[thread_num], NULL, rcv, NULL);
thread_num++;
pthread_create(&proc_thread[thread_num], NULL, snd, NULL);
thread_num++;
}

for(int i = 0; i < 3; i++)
{
pthread_join(proc_thread[i], NULL);
}

}//main

void *rcv (void *dummyPt)
{
cout << "Thread No: " << pthread_self() << endl;
char msg[300];
bzero(msg, 301);
while(1)
{
bzero(msg, 301);


read_size=read(client_sock, msg, 300);

string rcvmsg (msg);
cout <<  "\rOther:"  << rcvmsg << endl;
cout << "Me:";
fflush(stdout);


if ( rcvmsg =="quit") { break; }
else if ( read_size ==  0 ) { cout << "\rClient Diconnected" << endl; break; }
else if ( read_size == -1 ) { cout << "\rRecieve Failed" << endl; break; }

}//while
close(client_sock);
close(server_sock);
cout << "\rClosing thread and connection" << endl;
cout << "Ended." << endl;
exit(0);
}//rcv

void *snd (void *dummyPt)
{
cout << "Thread No: " << pthread_self() << endl;

while(1) {

char message[300];
cout << "Me:";
bzero(message, 301);
cin.getline(message, 300);

send(client_sock, message, strlen(message),0);

string sndmsg(message);

if ( sndmsg =="quit") {

break;

}//if

}//while

cout << "\rClosing thread and connection" << endl;
cout << "Ended." << endl;
close(client_sock);
close(server_sock);
exit(0);
}//snd

 

chatclient.cpp

 

 

#include <string.h>
#include <cstring>
#include <unistd.h>
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <strings.h>
#include <stdlib.h>
#include <string>
#include <time.h>
#include <vector>
using namespace std;

void *rcv(void *);
void *snd(void *);

static int client_sock;
static int read_size;

int main (int argc, char* argv[])
{
int port;
struct sockaddr_in server_address;
struct hostent *server;

pthread_t proc_thread[3];

if(argc < 3)
{
cerr<<"Syntax : ./chatclient <host name> <port>"<<endl;
return 0;
}

port = atoi(argv[2]);

if((port > 65535) || (port < 1024))
{
cerr<<"Please enter port number between 1024 - 65535"<<endl;
return 0;
}

client_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

if(client_sock < 0)
{
cerr << "Cannot open socket" << endl;
return 0;
}

server = gethostbyname(argv[1]);

if(server == NULL)
{
cerr << "Host does not exist" << endl;
return 0;
}

bzero((char *) &server_address, sizeof(server_address));
server_address.sin_family = AF_INET;

bcopy((char *) server -> h_addr, (char *) &server_address.sin_addr.s_addr, server -> h_length);

server_address.sin_port = htons(port);

int connection = connect(client_sock,(struct sockaddr *) &server_address, sizeof(server_address));

if (connection < 0)
{
cerr << "Cannot Connect!" << endl;
return 0;
}

int thread_num = 0;

while (thread_num <3 )
{

pthread_create(&proc_thread[thread_num], NULL, snd, NULL);
thread_num++;
pthread_create(&proc_thread[thread_num], NULL, rcv, NULL);
thread_num++;
}

for(int i = 0; i < 3; i++)
{
pthread_join(proc_thread[i], NULL);
}


}//main



void *rcv (void *dummyPt)
{
//cout << "Thread No: " << pthread_self() << endl;
char msg[300];
while(1)
{
bzero(msg, 301);


read_size=read(client_sock, msg, 300);

string rcvmsg (msg);
cout <<  "\rOther:"  << rcvmsg << endl;
cout << "Me:";
fflush(stdout);

if ( rcvmsg  =="quit") { break; }
else if ( read_size ==  0 ) { cout << "\rServer Closed Connection." << endl; break; }
else if ( read_size == -1 ) { cout << "\rRecieve Failed" << endl; break; }

}//while
cout << "\nClosing thread and connection" << endl;
cout << "Ended." << endl;
close(client_sock);
exit(0);
}//main

void *snd (void *dummyPt)
{
//cout << "Thread No: " << pthread_self() << endl;

while(1) {

char message[300];
cout << "\rMe:";
bzero(message, 301);
cin.getline(message, 300);

send(client_sock, message, strlen(message),0);
string sndmsg(message);

if ( sndmsg =="quit") {

break;

}//if

}//while
cout << "\nClosing thread and connection" << endl;
cout << "Ended." << endl;
close(client_sock);
exit(0);
}//snd

By: Mehdi Sadighian
Contact: mehdi.sadighian@hotmail.com
TAG: C, C++, socket programming, thread, multi thread, chat server, terminal chat, socket