diff --git a/RoboCat/Chapter3.vcxproj b/RoboCat/Chapter3.vcxproj
index 10d69fef..bf567325 100644
--- a/RoboCat/Chapter3.vcxproj
+++ b/RoboCat/Chapter3.vcxproj
@@ -381,11 +381,13 @@
+
+
diff --git a/RoboCat/Inc/OutputWindow.h b/RoboCat/Inc/OutputWindow.h
index a12ad9ef..73312118 100644
--- a/RoboCat/Inc/OutputWindow.h
+++ b/RoboCat/Inc/OutputWindow.h
@@ -1,3 +1,4 @@
+#pragma once
// Encapsulates a simulated "output window," where
// new messages are written from top to bottom
diff --git a/RoboCat/Inc/RoboCatPCH.h b/RoboCat/Inc/RoboCatPCH.h
index fa2871f8..9b5f8d1f 100644
--- a/RoboCat/Inc/RoboCatPCH.h
+++ b/RoboCat/Inc/RoboCatPCH.h
@@ -1,4 +1,4 @@
-
+#pragma once
#include
diff --git a/RoboCat/Inc/RoboCatShared.h b/RoboCat/Inc/RoboCatShared.h
index 83a3871a..3aa9061d 100644
--- a/RoboCat/Inc/RoboCatShared.h
+++ b/RoboCat/Inc/RoboCatShared.h
@@ -1,3 +1,5 @@
+#pragma once
+
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
diff --git a/RoboCat/Inc/SocketAddress.h b/RoboCat/Inc/SocketAddress.h
index 05bad2b8..0c8d5671 100644
--- a/RoboCat/Inc/SocketAddress.h
+++ b/RoboCat/Inc/SocketAddress.h
@@ -1,3 +1,5 @@
+#pragma once
+
class SocketAddress
{
public:
diff --git a/RoboCat/Inc/SocketAddressFactory.h b/RoboCat/Inc/SocketAddressFactory.h
index fe1e0516..1afaa5b8 100644
--- a/RoboCat/Inc/SocketAddressFactory.h
+++ b/RoboCat/Inc/SocketAddressFactory.h
@@ -1,3 +1,4 @@
+#pragma once
class SocketAddressFactory
diff --git a/RoboCat/Inc/SocketUtil.h b/RoboCat/Inc/SocketUtil.h
index 50a726c3..7238c192 100644
--- a/RoboCat/Inc/SocketUtil.h
+++ b/RoboCat/Inc/SocketUtil.h
@@ -1,3 +1,5 @@
+#pragma once
+
enum class SocketAddressFamily
{
INET = AF_INET,
diff --git a/RoboCat/Inc/StringUtils.h b/RoboCat/Inc/StringUtils.h
index b46b745d..2552708e 100644
--- a/RoboCat/Inc/StringUtils.h
+++ b/RoboCat/Inc/StringUtils.h
@@ -1,3 +1,5 @@
+#pragma once
+
namespace StringUtils
{
string GetCommandLineArg( int inIndex );
diff --git a/RoboCat/Inc/TCPSocket.h b/RoboCat/Inc/TCPSocket.h
index 0779a82b..3b3a42bd 100644
--- a/RoboCat/Inc/TCPSocket.h
+++ b/RoboCat/Inc/TCPSocket.h
@@ -1,3 +1,6 @@
+#pragma once
+
+
class TCPSocket
{
public:
diff --git a/RoboCat/Inc/UDPSocket.h b/RoboCat/Inc/UDPSocket.h
index 939df407..dcf105c3 100644
--- a/RoboCat/Inc/UDPSocket.h
+++ b/RoboCat/Inc/UDPSocket.h
@@ -1,4 +1,4 @@
-
+#pragma once
class UDPSocket
{
diff --git a/RoboCat/Src/ChatUser.cpp b/RoboCat/Src/ChatUser.cpp
new file mode 100644
index 00000000..4bdcc30a
--- /dev/null
+++ b/RoboCat/Src/ChatUser.cpp
@@ -0,0 +1,247 @@
+#include "RoboCatPCH.h"
+#include "ChatUser.h"
+#include
+#include
+
+// FUNCTION FROM user704565 AT https://stackoverflow.com/a/16286297:
+std::vector split(std::string str, std::string sep) {
+ char* cstr = const_cast(str.c_str());
+ char* current;
+ std::vector arr;
+ current = strtok(cstr, sep.c_str());
+ while (current != NULL) {
+ arr.push_back(current);
+ current = strtok(NULL, sep.c_str());
+ }
+ return arr;
+}
+
+ChatUser::ChatUser()
+{
+ SocketUtil::StaticInit();
+ sendSocket = SocketUtil::CreateTCPSocket(SocketAddressFamily::INET);
+ recvSocket = SocketUtil::CreateTCPSocket(SocketAddressFamily::INET);
+
+}
+
+ChatUser::~ChatUser()
+{
+ send("©DISCONNECT");
+ shutdown();
+ closeSockets();
+ SocketUtil::CleanUp();
+}
+
+void ChatUser::startTcpThread(bool isClient)
+{
+ username = isClient ? "Chat User 1" : "Chat User 2";
+
+ if (isClient)
+ t = std::thread([this] { initTcpClient(); });
+ else
+ t = std::thread([this] { initTcpServer(); });
+}
+
+void ChatUser::initTcpClient()
+{
+ sendRecvFlag = 0;
+
+ // Create socket
+ sendSocket = SocketUtil::CreateTCPSocket(SocketAddressFamily::INET);
+ if (sendSocket == nullptr)
+ {
+ SocketUtil::ReportError("Creating client socket");
+ ExitProcess(1);
+ }
+
+ LOG("%s", "Client socket created");
+
+ // Bind() - "Bind" socket -> tells OS we want to use a specific address
+
+ std::string address = StringUtils::Sprintf("127.0.0.1:%s", SEND_PORT.c_str());
+ SocketAddressPtr clientAddress = SocketAddressFactory::CreateIPv4FromString(address.c_str());
+ if (clientAddress == nullptr)
+ {
+ SocketUtil::ReportError("Creating client address");
+ ExitProcess(1);
+ }
+
+ if (sendSocket->Bind(*clientAddress) != NO_ERROR)
+ {
+ SocketUtil::ReportError("Binding client socket");
+ // This doesn't block!
+ ExitProcess(1);
+ }
+
+ LOG("%s", "Bound client socket");
+
+ // Connect() -> Connect socket to remote host
+
+ SocketAddressPtr servAddress = SocketAddressFactory::CreateIPv4FromString("127.0.0.1:"+RECV_PORT);
+ if (servAddress == nullptr)
+ {
+ SocketUtil::ReportError("Creating server address");
+ ExitProcess(1);
+ }
+ std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+ if (sendSocket->Connect(*servAddress) != NO_ERROR)
+ {
+ SocketUtil::ReportError("Connecting to server");
+ ExitProcess(1);
+ }
+
+ LOG("%s", "Connected to server!");
+ hasConnected = true;
+ send("©CONNECT");
+ quit = false;
+ std::thread receiveNewThread([&]() { // don't use [&] :)
+ while (!quit) // Need to add a quit here to have it really exit!
+ {
+ char buffer[4096];
+ int32_t bytesReceived = sendSocket->Receive(buffer, 4096);
+ if (bytesReceived == 0)
+ {
+ // handle disconnect
+ }
+ if (bytesReceived < 0)
+ {
+ SocketUtil::ReportError("Receiving");
+ return;
+ }
+
+ std::string receivedMsg(buffer, bytesReceived);
+ recv(receivedMsg);
+ }
+ });
+ receiveNewThread.join();
+}
+
+void ChatUser::initTcpServer()
+{
+ sendRecvFlag = 1;
+ // Create socket
+ recvSocket = SocketUtil::CreateTCPSocket(SocketAddressFamily::INET);
+ if (recvSocket == nullptr)
+ {
+ SocketUtil::ReportError("Creating listening socket");
+ ExitProcess(1);
+ }
+
+ //recvSocket->SetNonBlockingMode(true);
+
+ LOG("%s", "Listening socket created");
+
+ // Bind() - "Bind" socket -> tells OS we want to use a specific address
+
+ SocketAddressPtr listenAddress = SocketAddressFactory::CreateIPv4FromString("127.0.0.1:"+ RECV_PORT);
+ if (listenAddress == nullptr)
+ {
+ SocketUtil::ReportError("Creating listen address");
+ ExitProcess(1);
+ }
+
+ if (recvSocket->Bind(*listenAddress) != NO_ERROR)
+ {
+ SocketUtil::ReportError("Binding listening socket");
+ // This doesn't block!
+ ExitProcess(1);
+ }
+
+ LOG("%s", "Bound listening socket");
+
+ // Blocking function call -> Waits for some input; halts the program until something "interesting" happens
+ // Non-Blocking function call -> Returns right away, as soon as the action is completed
+
+ // Listen() - Listen on socket -> Non-blocking; tells OS we care about incoming connections on this socket
+ if (recvSocket->Listen() != NO_ERROR)
+ {
+ SocketUtil::ReportError("Listening on listening socket");
+ ExitProcess(1);
+ }
+
+ LOG("%s", "Listening on socket");
+
+ // Accept() - Accept on socket -> Blocking; Waits for incoming connection and completes TCP handshake
+
+ LOG("%s", "Waiting to accept connections...");
+ SocketAddress incomingAddress;
+ recvConnSocket = recvSocket->Accept(incomingAddress);
+ while (recvConnSocket == nullptr)
+ {
+ recvConnSocket = recvSocket->Accept(incomingAddress);
+ // SocketUtil::ReportError("Accepting connection");
+ // ExitProcess(1);
+ }
+ hasConnected = true;
+ send("©CONNECT");
+ LOG("Accepted connection from %s", incomingAddress.ToString().c_str());
+
+ quit = false;
+ std::thread receiveThread([&]() { // don't use [&] :)
+ while (!quit) // Need to add a quit here to have it really exit!
+ {
+ char buffer[4096];
+ int32_t bytesReceived = recvConnSocket->Receive(buffer, 4096);
+ if (bytesReceived == 0)
+ {
+ // handle disconnec
+ }
+ if (bytesReceived < 0)
+ {
+ SocketUtil::ReportError("Receiving");
+ return;
+ }
+
+ std::string receivedMsg(buffer, bytesReceived);
+ recv(receivedMsg);
+ }
+ });
+
+ receiveThread.join();
+}
+
+void ChatUser::send(std::string msg)
+{
+ if (strlen(msg.c_str()) > 0)
+ {
+ std::string toSend = username + "¦" + msg;
+ if (msg == "©DISCONNECT")
+ toSend = "©[SERVER]: " + username + " has disconnected!\n";
+ if (msg == "©CONNECT")
+ toSend = "©[SERVER]: " + username + " has connected!\n";
+
+ (sendRecvFlag == 0 ? sendSocket : recvConnSocket)->Send(toSend.c_str(), toSend.length());
+ }
+}
+
+void ChatUser::recv(std::string msg)
+{
+ if (msg[0] == '©')
+ {
+ std::cout << msg.erase(0, 1);
+ }
+ else
+ {
+ std::vector str = split(msg, "¦");
+ std::cout << ("[" + str[0] + "]: " + str[1] + "\n");
+ }
+}
+
+void ChatUser::closeSockets()
+{
+ if (sendRecvFlag == 0)
+ {
+ sendSocket->~TCPSocket();
+ }
+ else if (sendRecvFlag == 1)
+ {
+
+ recvConnSocket->~TCPSocket();
+ recvConnSocket->~TCPSocket();
+ }
+}
+
+void ChatUser::shutdown()
+{
+ quit = true;
+}
diff --git a/RoboCat/Src/ChatUser.h b/RoboCat/Src/ChatUser.h
new file mode 100644
index 00000000..324a8455
--- /dev/null
+++ b/RoboCat/Src/ChatUser.h
@@ -0,0 +1,33 @@
+#pragma once
+
+#include "RoboCatPCH.h"
+#include
+
+
+struct ChatUser
+{
+ OutputWindow win;
+ std::string username;
+ int sendRecvFlag = -1;
+ bool quit;
+ bool hasConnected = false;
+
+ const std::string SEND_PORT = "7000", RECV_PORT = "8080";
+
+ TCPSocketPtr sendSocket, recvSocket, recvConnSocket;
+ std::thread t;
+
+ ChatUser();
+ ~ChatUser();
+
+ void startTcpThread(bool isClient);
+
+ void initTcpClient();
+ void initTcpServer();
+
+ void send(std::string msg);
+ void recv(std::string msg);
+
+ void closeSockets();
+ void shutdown();
+};
\ No newline at end of file
diff --git a/RoboCat/Src/Main.cpp b/RoboCat/Src/Main.cpp
index f8c6c7d0..79bbebaf 100644
--- a/RoboCat/Src/Main.cpp
+++ b/RoboCat/Src/Main.cpp
@@ -5,9 +5,14 @@
#include
#include
#include
+#include "ChatUser.h"
#if _WIN32
+ChatUser* chatter = new ChatUser();
+std::thread tr1, tr2;
+bool run = true;
+
int main(int argc, const char** argv)
{
@@ -22,32 +27,31 @@ int main(int argc, const char** argv)
__argv = argv;
#endif
- SocketUtil::StaticInit();
-
- OutputWindow win;
-
- std::thread t([&win]()
- {
- int msgNo = 1;
- while (true)
- {
- std::this_thread::sleep_for(std::chrono::milliseconds(250));
- std::string msgIn("~~~auto message~~~");
- std::stringstream ss(msgIn);
- ss << msgNo;
- win.Write(ss.str());
- msgNo++;
- }
- });
-
- while (true)
+ std::cout << "User 1 or User 2? Enter number: ";
+ std::string userNumber = "1";
+ std::getline(std::cin, userNumber);
+ while (userNumber != "1" && userNumber != "2")
+ {
+ std::cout << "Invalid entry. Please enter 1 or 2: ";
+ std::getline(std::cin, userNumber);
+ }
+
+ chatter->startTcpThread(userNumber == "1");
+ std::cout << "Enter \"!EXIT\" at any point to exit. Case sensitive.\n";
+
+ while (run)
{
std::string input;
std::getline(std::cin, input);
- win.WriteFromStdin(input);
+
+ chatter->win.WriteFromStdin("[" + chatter->username + "]: " + input + "\n");
+ if (input == "!EXIT")
+ run = false;
+ else
+ chatter->send(input);
}
- SocketUtil::CleanUp();
+ delete chatter;
return 0;
}