commit 830c130ded1f6964a49e10b9ebdba132d8a6e883 Author: Your Name Date: Wed Feb 25 08:40:42 2026 -0600 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..8c4be5b --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +## ncursestest +A basic ncurses proof of concept test + +## network more complicated +A "complicated" network system that allows for ip address and port selection but dosn't use ncurses or have threading + +## network test +A better network test that doesn't allow you to use anything besides address 127.0.0.1 and port 8080 but it features properly implemented threading. The lack of ncurses prevents it from being passable as a client/server chat program because the ui gets out of sync but otherwise it actually works + +## thread test +A basic example of how to use pthread + +further instructions for how to use these programs are in the comments in their respective source code files \ No newline at end of file diff --git a/ncurses test/Makefile b/ncurses test/Makefile new file mode 100644 index 0000000..24bed10 --- /dev/null +++ b/ncurses test/Makefile @@ -0,0 +1,18 @@ +# Compiler and flags +CXX = g++ +CXXFLAGS = -Wall -Wextra -O2 -std=c++17 + +# Linker flags +LDFLAGS = -lcurses + +# Default target +all: ncursestest + +# Build rule +ncursestest: ncursestest.cpp + $(CXX) $(CXXFLAGS) ncursestest.cpp -o ncursestest $(LDFLAGS) + +# Clean build artifacts +clean: + rm -f ncursestest + diff --git a/ncurses test/ncursestest b/ncurses test/ncursestest new file mode 100755 index 0000000..b8a5929 Binary files /dev/null and b/ncurses test/ncursestest differ diff --git a/ncurses test/ncursestest.cpp b/ncurses test/ncursestest.cpp new file mode 100644 index 0000000..ceea411 --- /dev/null +++ b/ncurses test/ncursestest.cpp @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include +using namespace std; + +int main() +{ + initscr();//creates stdscr. important step + use_default_colors();//this apparently tells it to use default terminal colors whenever there is no color attribute applied + + printw("Hello World\n"); + printw("Please enter a string: "); + refresh(); + char *arr = new char[1024]; + getstr(arr); + printw("Wow I didn't think you'd type in THAT. You entered: "); + printw(arr); + + start_color(); + init_pair(1,COLOR_RED, COLOR_BLUE); + attron(COLOR_PAIR(1)); + printw("\nThe quick brown fox jumps over the lazy dog\n"); + attroff(COLOR_PAIR(1)); + + mvprintw(17, 7, "BRUUUUUUUUH"); + + move(12,13); + attron(A_STANDOUT | A_UNDERLINE); + mvprintw(15, 3, ""); + attroff(A_STANDOUT | A_UNDERLINE); + mvaddch(4,3, '@'); + refresh(); + getch(); + endwin(); +} diff --git a/network more complicated/Makefile b/network more complicated/Makefile new file mode 100644 index 0000000..076c037 --- /dev/null +++ b/network more complicated/Makefile @@ -0,0 +1,19 @@ +# Compiler and flags +CXX = g++ +CXXFLAGS = -Wall -Wextra -O2 -std=c++17 + +# Targets +all: client server + +# Client build +client: client.cpp + $(CXX) $(CXXFLAGS) client.cpp -o client + +# Server build +server: server.cpp + $(CXX) $(CXXFLAGS) server.cpp -o server + +# Clean build artifacts +clean: + rm -f client server + diff --git a/network more complicated/client b/network more complicated/client new file mode 100755 index 0000000..97b22b6 Binary files /dev/null and b/network more complicated/client differ diff --git a/network more complicated/client.cpp b/network more complicated/client.cpp new file mode 100644 index 0000000..bd58677 --- /dev/null +++ b/network more complicated/client.cpp @@ -0,0 +1,86 @@ +/*this network test uses more complicated network functionality but doesnt use threads or ncurses. +that means you have to wait for the other end to send a message before getting to write a new message +to run, do ./client.cpp 127.0.0.1 8080 +this one has args +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +//Client side +int main(int argc, char *argv[]) +{ + //we need 2 things: ip address and port number, in that order + if(argc != 3) + { + cerr << "Usage: ip_address port" << endl; exit(0); + } //grab the IP address and port number + char *serverIp = argv[1]; int port = atoi(argv[2]); + //create a message buffer + char msg[1500]; + //setup a socket and connection tools + struct hostent* host = gethostbyname(serverIp); + sockaddr_in sendSockAddr; + bzero((char*)&sendSockAddr, sizeof(sendSockAddr)); + sendSockAddr.sin_family = AF_INET; + sendSockAddr.sin_addr.s_addr = + inet_addr(inet_ntoa(*(struct in_addr*)*host->h_addr_list)); + sendSockAddr.sin_port = htons(port); + int clientSd = socket(AF_INET, SOCK_STREAM, 0); + //try to connect... + int status = connect(clientSd, + (sockaddr*) &sendSockAddr, sizeof(sendSockAddr)); + if(status < 0) + { + cout<<"Error connecting to socket!"<"; + string data; + getline(cin, data); + memset(&msg, 0, sizeof(msg));//clear the buffer + strcpy(msg, data.c_str()); + if(data == "exit") + { + send(clientSd, (char*)&msg, strlen(msg), 0); + break; + } + bytesWritten += send(clientSd, (char*)&msg, strlen(msg), 0); + cout << "Awaiting server response..." << endl; + memset(&msg, 0, sizeof(msg));//clear the buffer + bytesRead += recv(clientSd, (char*)&msg, sizeof(msg), 0); + if(!strcmp(msg, "exit")) + { + cout << "Server has quit the session" << endl; + break; + } + cout << "Server: " << msg << endl; + } + gettimeofday(&end1, NULL); + close(clientSd); + cout << "********Session********" << endl; + cout << "Bytes written: " << bytesWritten << + " Bytes read: " << bytesRead << endl; + cout << "Elapsed time: " << (end1.tv_sec- start1.tv_sec) + << " secs" << endl; + cout << "Connection closed" << endl; + return 0; +} \ No newline at end of file diff --git a/network more complicated/server b/network more complicated/server new file mode 100755 index 0000000..900e9da Binary files /dev/null and b/network more complicated/server differ diff --git a/network more complicated/server.cpp b/network more complicated/server.cpp new file mode 100644 index 0000000..a0e569f --- /dev/null +++ b/network more complicated/server.cpp @@ -0,0 +1,117 @@ +/*this network test uses more complicated network functionality but doesnt use threads or ncurses. +that means you have to wait for the other end to send a message before getting to write a new message +to run, do ./server.cpp 8080 +this one has args +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +//Server side +int main(int argc, char *argv[]) +{ + //for the server, we only need to specify a port number + if(argc != 2) + { + cerr << "Usage: port" << endl; + exit(0); + } + //grab the port number + int port = atoi(argv[1]); + //buffer to send and receive messages with + char msg[1500]; + + //setup a socket and connection tools + sockaddr_in servAddr; + bzero((char*)&servAddr, sizeof(servAddr)); + servAddr.sin_family = AF_INET; + servAddr.sin_addr.s_addr = htonl(INADDR_ANY); + servAddr.sin_port = htons(port); + + //open stream oriented socket with internet address + //also keep track of the socket descriptor + int serverSd = socket(AF_INET, SOCK_STREAM, 0); + if(serverSd < 0) + { + cerr << "Error establishing the server socket" << endl; + exit(0); + } + //bind the socket to its local address + int bindStatus = bind(serverSd, (struct sockaddr*) &servAddr, + sizeof(servAddr)); + if(bindStatus < 0) + { + cerr << "Error binding socket to local address" << endl; + exit(0); + } + cout << "Waiting for a client to connect..." << endl; + //listen for up to 5 requests at a time + listen(serverSd, 5); + //receive a request from client using accept + //we need a new address to connect with the client + sockaddr_in newSockAddr; + socklen_t newSockAddrSize = sizeof(newSockAddr); + //accept, create a new socket descriptor to + //handle the new connection with client + int newSd = accept(serverSd, (sockaddr *)&newSockAddr, &newSockAddrSize); + if(newSd < 0) + { + cerr << "Error accepting request from client!" << endl; + exit(1); + } + cout << "Connected with client!" << endl; + //lets keep track of the session time + struct timeval start1, end1; + gettimeofday(&start1, NULL); + //also keep track of the amount of data sent as well + int bytesRead, bytesWritten = 0; + while(1) + { + //receive a message from the client (listen) + cout << "Awaiting client response..." << endl; + memset(&msg, 0, sizeof(msg));//clear the buffer + bytesRead += recv(newSd, (char*)&msg, sizeof(msg), 0); + if(!strcmp(msg, "exit")) + { + cout << "Client has quit the session" << endl; + break; + } + cout << "Client: " << msg << endl; + cout << ">"; + string data; + getline(cin, data); + memset(&msg, 0, sizeof(msg)); //clear the buffer + strcpy(msg, data.c_str()); + if(data == "exit") + { + //send to the client that server has closed the connection + send(newSd, (char*)&msg, strlen(msg), 0); + break; + } + //send the message to client + bytesWritten += send(newSd, (char*)&msg, strlen(msg), 0); + } + //we need to close the socket descriptors after we're all done + gettimeofday(&end1, NULL); + close(newSd); + close(serverSd); + cout << "********Session********" << endl; + cout << "Bytes written: " << bytesWritten << " Bytes read: " << bytesRead << endl; + cout << "Elapsed time: " << (end1.tv_sec - start1.tv_sec) + << " secs" << endl; + cout << "Connection closed..." << endl; + return 0; +} \ No newline at end of file diff --git a/network test/Makefile b/network test/Makefile new file mode 100644 index 0000000..076c037 --- /dev/null +++ b/network test/Makefile @@ -0,0 +1,19 @@ +# Compiler and flags +CXX = g++ +CXXFLAGS = -Wall -Wextra -O2 -std=c++17 + +# Targets +all: client server + +# Client build +client: client.cpp + $(CXX) $(CXXFLAGS) client.cpp -o client + +# Server build +server: server.cpp + $(CXX) $(CXXFLAGS) server.cpp -o server + +# Clean build artifacts +clean: + rm -f client server + diff --git a/network test/client b/network test/client new file mode 100755 index 0000000..fadc819 Binary files /dev/null and b/network test/client differ diff --git a/network test/client.cpp b/network test/client.cpp new file mode 100644 index 0000000..4c85989 --- /dev/null +++ b/network test/client.cpp @@ -0,0 +1,94 @@ + +// Client side C/C++ program to demonstrate Socket programming +//this uses threads to allow a server and a client to do network chat stuff over 127.0.0.1:8080. the ui is out of sync because it doesn't use ncurses but the message sending and printing part still works +#include +#include +#include +#include +#include +#include +#include +#include +#define PORT 8080 +using namespace std; + +#ifdef _WIN32 + /#include ; + void fnsleep(unsigned milliseconds) + { + Sleep(milliseconds); + } + +#else + #include + void fnsleep(unsigned milliseconds) + { + usleep(milliseconds * 1000); + } +#endif + +void checkForNewMsgs(int socket, int valreaded, int otherNum); + +void checkForNewMsgs(int socket, int valreaded, int otherNum) +{ + int valreadOne; + char newBuffer[1024] = {0}; + while (3 == 3 && newBuffer != "exit") + { + for(int i = 0; i < 1024; i++) + { + newBuffer[i] = char(0); + } + valreadOne = read( socket , newBuffer, 1024); + if (newBuffer != "") + { + cout << "Server: "; + printf("%s\n",newBuffer ); + } + } + fnsleep(1000); + +} + +int main(int argc, char const *argv[]) +{ + int sock = 0, valread; + struct sockaddr_in serv_addr; + char *hello = "Hello from client"; + char buffer[1024] = {0}; + if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) + { + printf("\n Socket creation error \n"); + return -1; + } + + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(PORT); + + // Convert IPv4 and IPv6 addresses from text to binary form + if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0) + { + printf("\nInvalid address/ Address not supported \n"); + return -1; + } + + if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) + { + printf("\nConnection Failed \n"); + return -1; + } + string message; + thread t(checkForNewMsgs, sock, valread, 1024); + t.detach(); + while (message != "exit") + { + cout << "> "; + getline(cin, message); + send(sock , message.c_str() , strlen(message.c_str()) , 0 ); + + //printf("Hello message sent\n"); + //valread = read( sock , buffer, 1024); + //printf("%s\n",buffer ); + } + return 0; +} diff --git a/network test/server b/network test/server new file mode 100755 index 0000000..95b7882 Binary files /dev/null and b/network test/server differ diff --git a/network test/server.cpp b/network test/server.cpp new file mode 100644 index 0000000..950bf8f --- /dev/null +++ b/network test/server.cpp @@ -0,0 +1,114 @@ + +// Server side C/C++ program to demonstrate Socket programming +//this uses threads to allow a server and a client to do network chat stuff over 127.0.0.1:8080. the ui is out of sync because it doesn't use ncurses but the message sending and printing part still works +#include +#include +#include +#include +#include +#include +#include +#include +using namespace std; +#define PORT 8080 + +#ifdef _WIN32 + /#include ; + void fnsleep(unsigned milliseconds) + { + Sleep(milliseconds); + } + +#else + #include + void fnsleep(unsigned milliseconds) + { + usleep(milliseconds * 1000); + } +#endif + +void checkForNewMsgs(int socket, int valreaded, int otherNum); + +void checkForNewMsgs(int socket, int valreaded, int otherNum) +{ + int valreadOne; + char newBuffer[1024] = {0}; + while (3 == 3 && newBuffer != "exit") + { + //printf("Client: "); + for(int i = 0; i < 1024; i++) + { + newBuffer[i] = char(0); + } + valreadOne = read( socket , newBuffer, 1024); + if (newBuffer != "") + { + printf("Client: "); + printf("%s\n",newBuffer ); + } + } + fnsleep(1000); + +} + +int main(int argc, char const *argv[]) +{ + int server_fd, new_socket, valread; + struct sockaddr_in address; + int opt = 1; + int addrlen = sizeof(address); + char buffer[1024] = {0}; + char *hello = "Hello from server"; + + // Creating socket file descriptor + if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) + { + perror("socket failed"); + exit(EXIT_FAILURE); + } + + // Forcefully attaching socket to the port 8080 + if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, + &opt, sizeof(opt))) + { + perror("setsockopt"); + exit(EXIT_FAILURE); + } + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons( PORT ); + + // Forcefully attaching socket to the port 8080 + if (bind(server_fd, (struct sockaddr *)&address, + sizeof(address))<0) + { + perror("bind failed"); + exit(EXIT_FAILURE); + } + if (listen(server_fd, 3) < 0) + { + perror("listen"); + exit(EXIT_FAILURE); + } + if ((new_socket = accept(server_fd, (struct sockaddr *)&address, + (socklen_t*)&addrlen))<0) + { + perror("accept"); + exit(EXIT_FAILURE); + } + + string message; + thread t(checkForNewMsgs, new_socket, valread, 1024); + t.detach(); + while (message != "exit") + { + //string message; + cout << "> "; + getline(cin, message); + //valread = read( new_socket , buffer, 1024); + //printf("%s\n",buffer ); + send(new_socket , message.c_str() , strlen(message.c_str()) , 0 ); + //cout << "Hello message sent" << endl; + } + return 0; +} diff --git a/thread test/Makefile b/thread test/Makefile new file mode 100644 index 0000000..70ea492 --- /dev/null +++ b/thread test/Makefile @@ -0,0 +1,21 @@ +# Compiler and flags +CXX = g++ +CXXFLAGS = -pthread -Wall -Wextra -O2 -std=c++17 + +# Linker flags +LDFLAGS = -lcurses + +# Default target +all: thread threadncurses + +# Build rule +thread: thread.cpp + $(CXX) $(CXXFLAGS) thread.cpp -o thread $(LDFLAGS) + +threadncurses: threadncurses.cpp + $(CXX) $(CXXFLAGS) threadncurses.cpp -o threadncurses $(LDFLAGS) + +# Clean build artifacts +clean: + rm -f thread threadncurses + diff --git a/thread test/thread b/thread test/thread new file mode 100755 index 0000000..912770b Binary files /dev/null and b/thread test/thread differ diff --git a/thread test/thread.cpp b/thread test/thread.cpp new file mode 100644 index 0000000..b7e619a --- /dev/null +++ b/thread test/thread.cpp @@ -0,0 +1,49 @@ +//compile with "g++ -pthread thread.cpp -o main" +//note to self: try to use ncurses in the next one +#include +#include +#include +#include +using namespace std; + +#ifdef _WIN32 + //this part has never been tested and is unlikely to work + #include ; + void fnsleep(unsigned milliseconds) + { + Sleep(milliseconds); + } + +#else + #include + void fnsleep(unsigned milliseconds) + { + usleep(milliseconds * 1000); + } +#endif + +void helloWorld(int y) +{ + for (int i = 0; i < 10; i++) + { + //a terrible, awful way of getting linux terminal text colors without ncurses. + cout << "\033[1;31mbold red text\033[0m\n"; + cout << "\x1B[32mAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x1B[0m\n"; + cout << "Hello world #" << i + 1 << endl; + fnsleep(1000); + } +} + +int main() +{ + thread thread_object(helloWorld, 1); + cout << "This string gets printed after running the hello world function but prints BEFORE helloworld prints. That means this program uses threads" << endl; + //use detach to make the thread run asychronoussly. use join to WAIT HERE until its finished. Try it out! (i tested both cases and it works on my machine) + //thread_object.detach(); + thread_object.join(); + cout << "Please enter your name: " << endl; + string name; + cin >> name; + cout << name << " is a [redacted for academic purposes]" << endl; + return 0; +} \ No newline at end of file diff --git a/thread test/threadncurses b/thread test/threadncurses new file mode 100755 index 0000000..611b0eb Binary files /dev/null and b/thread test/threadncurses differ diff --git a/thread test/threadncurses.cpp b/thread test/threadncurses.cpp new file mode 100644 index 0000000..00c118a --- /dev/null +++ b/thread test/threadncurses.cpp @@ -0,0 +1,90 @@ +//compile with "g++ -pthread threadncurses.cpp -o main -lncurses" +//the same as thread.cpp but it uses ncurses instead. This proves that ncurses can work even if its in a seperate thread +//this is a very functional example of ncurses and asynchronous threading working in the same program +#include +#include +#include +#include +#include +using namespace std; + +#ifdef _WIN32 + //this part has never been tested and is unlikely to work + #include ; + void fnsleep(unsigned milliseconds) + { + Sleep(milliseconds); + } + +#else + #include + void fnsleep(unsigned milliseconds) + { + usleep(milliseconds * 1000); + } +#endif + +void helloWorld(int y) +{ + for (int i = 0; i < 10; i++) + { + //store the cursor positions here + int y, x; + int yy, xx; + int xBefore; + int yBefore; + start_color(); + init_pair(1, COLOR_RED, COLOR_BLUE); + if (i != 0) + { + //print the hello world lines + getyx(stdscr, yBefore, xBefore); + move(2, 0); + clrtoeol(); + mvprintw(2, 0, "Hello world #"); + int icantthinkofanameforthis = i + 1; + printw(to_string(icantthinkofanameforthis).c_str());//an annoying but reliable way to get this to work + printw("\n"); + move(yBefore, xBefore); //move the cursor back to where is was before to allow for a fluid typing experience (i.e. its possible to mess this part up if you do it wrong) + } + else + { + attron(COLOR_PAIR(1)); + attron(A_BOLD); + getyx(stdscr, yy, xx); + printw("bold red text\n"); + attroff(COLOR_PAIR(1)); + printw("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"); + attroff(A_BOLD); + printw("Hello world #"); + int icantthinkofanameforthis = i + 1; + printw(to_string(icantthinkofanameforthis).c_str());//an annoying but reliable way to get this to work + printw("\n"); + move(3, 25); //the default text-entry position + } + + refresh(); + fnsleep(1000); + } +} + +int main() +{ + initscr(); + use_default_colors(); + move(3, 0); + printw("Please enter your name: \n"); + move(0, 0); + + thread thread_object(helloWorld, 1); + thread_object.detach(); + + char *name = new char[99]; + getstr(name); + printw(name); + printw(" is a [redacted for academic purposes]\n"); + printw("Press any key to continue"); + getch(); + endwin(); + return 0; +} \ No newline at end of file