Code:
//***INCLUDES***
#include <fstream.h> //for cout and cin, and to potentially keep a log of your chat
#include <winsock.h> //for sockets and WSADATA data structures
#include <string.h> //string functions
#include <ctype.h> //toupper function
#include <cstdlib.h> //for the exit() function
#include <conio.h> //allows use of color and clrscr();
#include <iomanip.h> //lets one use the setbase() command
using namespace std;
//***GLOBAL CONSTANTS***
const short int WINSOCK_VERSION = 0x0202;
const int PORT = 3163; //the port used for data sending
const int MAX_LEN = 4096;
//***FUNCTION PROTOTYPES***
void start_winsock(WSADATA& data);
//precondition: WSADATA structure has been declared
//postcondition: Either Winsock started up or the program ended if there was an initialization error
void output_winsock_data(WSADATA data);
//precondition: WSADATA structure has been declared
//postcondition: Information pertaining to Winsock has been outputted
void open_socket(SOCKET& MySocket);
//precondition: MySocket has been declared
//postcondition: If socket() could not be opened, the program terminates
void chat_server(SOCKET& MySocket, bool& contin);
void chat_client(SOCKET& MySocket, bool& contin);
void bind_socket(SOCKET& MySocket, SOCKADDR_IN& bindToAddress);
void listen_on_stream_socket(SOCKET& MySocket);
void accept_msg_socket(SOCKET& MySocket, SOCKET& theClient, SOCKADDR_IN& fromAddress, int& length);
void receive_message(SOCKET& theClient, char incoming[MAX_LEN]);
void find_host(char Server[MAX_LEN], hostent* host, int& address, SOCKADDR_IN& remoteAddress);
void connect_host(SOCKET& MySocket, SOCKADDR_IN& remoteAddress);
void send_reply(SOCKET& Socket, char outgoing[MAX_LEN]);
void changecolor(char* word, int color);
//precondition: word has been given a string value, and color has been given a number
//postcondition: conio function textcolor() has been called within function changecolor,
//changing the char* word into the color given by the int color.
void slowtype(char* word);
//precondition: word has a value
//postcondition: word has been outputted slowly (one letter per 70 milliseconds)
void flushin();
//***FUNCTION BODIES***
int main(){
SOCKET MySocket; // create the socket itself
WSADATA data; //contains data pertaining to WinSock
char abc;
bool contin = true;
changecolor("Nakeerb's Chat Program\r\n\r\n", LIGHTRED);
changecolor("Utilizing #include <winsock>...\r\n", LIGHTGREEN);
cout << setbase(16) << "Version: " << WINSOCK_VERSION << endl;
slowtype("Initializing WSAStartup:\n");
start_winsock(data);
output_winsock_data(data);
open_socket(MySocket);
cout << "Press a key to continue.\n";
getch();
do{
clrscr();
cout << "\n\n\n";
changecolor("MENU:\r\n", WHITE);
changecolor("(A). Chat Server (I want someone to connect to me)\r\n", LIGHTBLUE);
changecolor("(B). Chat Client (I want to choose someone to talk to)\r\n", LIGHTBLUE);
changecolor("CHOICE: ", LIGHTGREEN);
cin >> abc;
switch(toupper(abc)){
case 'A':
chat_server(MySocket, contin); //you will wait for someone to connect to you
break;
case 'B':
chat_client(MySocket, contin); //you get to choose someone to speak to
break;
case 'C':
//insert IP and hostname output here
default:
cout << "I don't understand\n";
}
}while(contin);
WSACleanup(); // Shutdown Winsock
getch();
return 0;
}
void start_winsock(WSADATA& data){
if(WSAStartup(WINSOCK_VERSION,&data) != 0){ //begins Winsock, but exits if there is initialiation error
cout << "ERROR!! Windows sockets were unable to initialize.\n"
<< "WSAStartup did not return a 0, something is amiss...\n";
getch();
exit(1);
}
} //end void start_winsock
void output_winsock_data(WSADATA data){
cout << "Windows sockets initialized" << endl << endl;
cout << "WSAStartup data returned: " << endl;
slowtype("wVersion: ");
cout << data.wVersion << endl;
slowtype("wHighVersion: ");
cout << data.wHighVersion << endl;
cout << setbase(10);
slowtype("szDescription: ");
cout << data.szDescription << endl;
slowtype("szSystemStatus: ");
cout << data.szSystemStatus << endl;
} //end void output_winsock_data
void open_socket(SOCKET& MySocket){
MySocket = socket(AF_INET, SOCK_STREAM, 0); // Go over TCP/IP, socket type, protocol
//IPPROTO_TCP
if (MySocket == INVALID_SOCKET) { //unable to open socket
printf("Error, socket() unabled to be opened");
getch();
WSACleanup(); //End Winsock
exit(1);
}
} //end void open_socket
void chat_server(SOCKET& MySocket, bool& contin){
SOCKET theClient; //used for incoming connection socket
SOCKADDR_IN bindToAddress; // Use SOCKADDR_IN to fill in address information
SOCKADDR_IN fromAddress;
char incoming[MAX_LEN];
char outgoing[MAX_LEN];
char charnum[30];
int length = sizeof(fromAddress);
bindToAddress.sin_family = AF_INET;
bindToAddress.sin_port = htons(PORT); //converts for the port field in correct byte order
bindToAddress.sin_addr.s_addr = INADDR_ANY; // Since this is a server, any address will do
bind_socket(MySocket, bindToAddress);
listen_on_stream_socket(MySocket);
clrscr();
changecolor("Listening for a connection from TCP port ", LIGHTGREEN);
sprintf(charnum, "%d", PORT); //word used as buffer
changecolor(charnum, WHITE);
cout << "...\n-----------------------------------------------" << endl;
accept_msg_socket(MySocket, theClient, fromAddress, length);
clrscr();
changecolor(inet_ntoa(fromAddress.sin_addr), LIGHTGREEN);
cout << " has connected to you. Chatting...\n\n\n";
flushin();
do{
changecolor("Wait for reply...\r\n", LIGHTGREEN);
receive_message(theClient, incoming);
changecolor(inet_ntoa(fromAddress.sin_addr), LIGHTRED);
changecolor(": ", LIGHTRED);
changecolor(incoming, WHITE);
cout << endl;
changecolor("Your message: ", LIGHTBLUE);
cin.getline(outgoing, MAX_LEN);
send_reply(theClient, outgoing);
} while(1);
} //end void chat_server
void chat_client(SOCKET& MySocket, bool& contin){
SOCKADDR_IN remoteAddress;
hostent* host;
u_long machineIP;
char Server[MAX_LEN];
char incoming[MAX_LEN];
char outgoing[MAX_LEN];
int address;
clrscr();
cout << "Type an IP Address or Hostname to connect to" << endl;
cin >> Server;
cout << endl;
find_host(Server, host, address, remoteAddress);
connect_host(MySocket, remoteAddress);
flushin();
do{
changecolor("Your Message: ", LIGHTBLUE);
cin.getline(outgoing, MAX_LEN);
send_reply(MySocket, outgoing);
changecolor("Wait for reply...\r\n", LIGHTGREEN);
receive_message(MySocket, incoming);
changecolor(inet_ntoa(remoteAddress.sin_addr), LIGHTRED);
changecolor(": ", LIGHTRED);
changecolor(incoming, WHITE);
cout << endl;
}while(1); //run forever
} //end void chat_client
void bind_socket(SOCKET& MySocket, SOCKADDR_IN& bindToAddress){
if(bind(MySocket, (struct sockaddr*)&bindToAddress, sizeof(bindToAddress)) == SOCKET_ERROR){ //binds socket
cout << "Error binding socket" << endl; //if it can't cast sockaddr_in to sockaddr*, exit
getch();
WSACleanup();
exit(1);
}
} //end void bind_socket
void listen_on_stream_socket(SOCKET& MySocket){
if (listen(MySocket,5) == SOCKET_ERROR){ //5 is the number of clients that can be queued
cout << "Error listening on socket" << endl;
getch();
WSACleanup();
exit(1);
}
} //end void listen_on_stream_socket
void accept_msg_socket(SOCKET& MySocket, SOCKET& theClient, SOCKADDR_IN& fromAddress, int& length){
theClient = accept(MySocket,(struct sockaddr*)&fromAddress, &length);
//server Socket, Address sockaddr structure, Address var containing size of sockaddr
if (theClient == INVALID_SOCKET){
cout << "Error accepting connection on message socket!!" << endl;
getch();
WSACleanup();
exit(1);
}
} //end void accept_msg_socket
void receive_message(SOCKET& Socket, char incoming[MAX_LEN]){
if(recv(Socket,incoming,sizeof(incoming), 0) == SOCKET_ERROR){ //Connected socket, receive buffer, no flags
cout << "Error receiving data from message socket into buffer!" << endl;
getch();
WSACleanup();
exit(1);
}
} //end void receive_message
void find_host(char Server[MAX_LEN], hostent* host, int& address, SOCKADDR_IN& remoteAddress){
if (isalpha(Server[0])) //Server IP is a hostname because it's in English letters
host = gethostbyname(Server); //gets the host by the name of the server
else{ //Server is an IP Address, must be numbers
address = inet_addr(Server); // convert address and lookup hostname
host = gethostbyaddr((char *)&address,sizeof(address),AF_INET);
}
if (host == NULL ){ //you entered nothing? You fool.
cout << "Cannot resolve address " << Server << endl;
getch();
WSACleanup();
exit(1);
}
remoteAddress.sin_family = AF_INET;
remoteAddress.sin_port = htons(PORT);
if (host!=NULL){ //the host exists
memcpy(&(remoteAddress.sin_addr),host -> h_addr,host -> h_length); //store address
cout << "Found " << Server << " without any errors." << endl
<< "IP Address: " << inet_ntoa(remoteAddress.sin_addr) << endl
<< "Hostname: " << host -> h_name << endl;
}
} //end void find_host
void connect_host(SOCKET& MySocket, SOCKADDR_IN& remoteAddress){
cout << "\nAbout to connect to " << inet_ntoa(remoteAddress.sin_addr) << "... press a key." << endl;
getch();
if(connect(MySocket,(struct sockaddr*)&remoteAddress, sizeof(remoteAddress)) == SOCKET_ERROR){
cout << "The connection was a complete and utter failure, too bad!" << endl;
getch();
WSACleanup();
exit(1);
}
cout << "Connected with ";
changecolor(inet_ntoa(remoteAddress.sin_addr), LIGHTGREEN);
cout << "...\n---------------------------------------------\n\n";
} //end void connect_host
void send_reply(SOCKET& Socket, char outgoing[MAX_LEN]){
if(send(Socket,outgoing,sizeof(outgoing),0) == SOCKET_ERROR){
cout << "Error sending reply" << endl;
getch();
WSACleanup();
exit(1);
}
} //end void send_reply
void changecolor(char* word, int color){
textcolor(color); //changes text to the color given through the argument
cprintf("%s", word); //outputs the string in the given color
textcolor(LIGHTGRAY); //change color back to the default light gray
} //end void changecolor
void slowtype(char* word){
for (int i = 0; word[i] != '\0'; i++){
cout << word[i];
Sleep(70);
} //outputs text slowly
Sleep(30);
} //end void slowtype
void flushin(){
while (cin.get() != '\n'){}
}
It all works except for that damn output from the other user. What is going wrong!?