From c85581749bede35bf37d15f40d384e8b0d41ed50 Mon Sep 17 00:00:00 2001 From: Dustin Thomas Date: Wed, 26 Mar 2025 15:28:16 -0500 Subject: [PATCH] first attempt at networking (does not work) --- README.md | 4 +-- client.cpp | 40 ++++++++++++++++++++++++++++-- packets/ImagePacket.cpp | 54 +++++++++++++++++++++++++++-------------- packets/ImagePacket.h | 14 ++++++++--- server.cpp | 45 ++++++++++++++++++++++++++++++---- 5 files changed, 126 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 2d717c2..e5db22f 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,6 @@ meson build server # for server only ## Running ```shell -./build/client -./build/server +./build/client # for client application +./build/server # for server application ``` \ No newline at end of file diff --git a/client.cpp b/client.cpp index 6b47673..5d30c19 100644 --- a/client.cpp +++ b/client.cpp @@ -1,10 +1,46 @@ -#include #include +#include +#include +#include +#include +#include +#include using namespace std; int main() { cv::VideoCapture cap = cv::VideoCapture(0); - cout << "Hello World!" << endl; + + int clientSocket = socket(AF_INET, SOCK_STREAM, 0); + + // specifying address + sockaddr_in serverAddress; + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(8080); + serverAddress.sin_addr.s_addr = INADDR_ANY; + + cv::Mat image = cv::Mat::zeros(cv::Size(640, 480), CV_8UC3); + ImagePacket packet = ImagePacket(&image, 0); + + // sending connection request + connect(clientSocket, (struct sockaddr*)&serverAddress, + sizeof(serverAddress)); + + unsigned long pos = 0; + unsigned long len = image.total() * image.elemSize(); + char buffer[IMAGEPACKET_SIZE]; + + cout << "Image length " << len << endl; + + while (true) { + cap.read(image); + packet = ImagePacket(&image, pos); + packet.serialize(buffer); + send(clientSocket, buffer, sizeof(buffer), 0); + cout << "Sent packet with index " << pos << endl; + pos = (pos + SLICE_SIZE) % len; + } + + close(clientSocket); return 0; } \ No newline at end of file diff --git a/packets/ImagePacket.cpp b/packets/ImagePacket.cpp index 113a135..8fb26f8 100644 --- a/packets/ImagePacket.cpp +++ b/packets/ImagePacket.cpp @@ -1,38 +1,56 @@ #include "ImagePacket.h" -/* - * Construct a packet from an OpenCV Mat, and a beginning index. It will take PACKET_SIZE bytes from the start and add - * it to its slice - */ -ImagePacket::ImagePacket(const cv::Mat *image, const int begin) { - const uchar *target = &image->data[begin]; - // TODO: handle out of index cases, pad with zeroes. probably also instantiate our byte array with zeroes - for (int i = 0; i < PACKET_SIZE; i++) { - slice[i] = target[begin + i]; - } -} - /* * Construct a packet from a raw array of unsigned chars, and a beginning index. It will take PACKET_SIZE bytes from the * start and add it to its slice. This will be more useful for embedded scenarios where OpenCV will likely not be used. */ ImagePacket::ImagePacket(const uchar *image, const int begin) { + this->begin = begin; + this->slice = new uchar[SLICE_SIZE]; const uchar *target = &image[begin]; // TODO: handle out of index cases, pad with zeroes. probably also instantiate our byte array with zeroes - for (int i = 0; i < PACKET_SIZE; i++) { - slice[i] = target[begin + i]; + for (int i = 0; i < SLICE_SIZE; i++) { + this->slice[i] = target[begin + i]; } } +/* + * destructor frees memory + */ +ImagePacket::~ImagePacket() = default; + +unsigned long ImagePacket::getBegin() const { + return this->begin; +} + + /* * Apply the packet to an OpenCV Mat. */ int ImagePacket::apply(const cv::Mat *image) const { - uchar *target = &image->data[begin]; + uchar *target = &image->data[this->begin]; // TODO: handle out of index cases - for (int i = 0; i < PACKET_SIZE; i++) { - target[begin + i] = slice[i]; + for (int i = 0; i < SLICE_SIZE; i++) { + target[this->begin + i] = this->slice[i]; } // TODO: return the actual written size of the packet - return PACKET_SIZE; + return SLICE_SIZE; } + +/* + * Serialize the object into a byte array + */ +void ImagePacket::serialize(char* buffer) const { + // TODO: keep the endianness consistent between systems + std::memcpy(buffer, &this->begin, sizeof(this->begin)); + std::memcpy(buffer + sizeof(this->begin), &this->slice, SLICE_SIZE * sizeof(uchar)); +} + +/* + * Deserialize the object from a byte array + */ +void ImagePacket::deserialize(char* buffer) { + // TODO: keep the endianness consistent between systems + std::memcpy(&this->begin, buffer, sizeof(this->begin)); + std::memcpy(this->slice, buffer + sizeof(this->begin), SLICE_SIZE * sizeof(uchar)); +} \ No newline at end of file diff --git a/packets/ImagePacket.h b/packets/ImagePacket.h index caa7da6..90b2ad8 100644 --- a/packets/ImagePacket.h +++ b/packets/ImagePacket.h @@ -2,17 +2,23 @@ #define IMAGEPACKET_H #include -#define PACKET_SIZE 768 +#define SLICE_SIZE 768 +#define IMAGEPACKET_SIZE sizeof(int) + (SLICE_SIZE * sizeof(uchar)) class ImagePacket { public: - ImagePacket(const cv::Mat *image, int begin); + ImagePacket(const cv::Mat *image, int begin) : ImagePacket(image->data, begin) {} ImagePacket(const uchar *image, int begin); + ~ImagePacket(); + + unsigned long getBegin() const; int apply(const cv::Mat *image) const; + void serialize(char* buffer) const; + void deserialize(char* buffer); private: - int begin; - uchar slice[PACKET_SIZE]; + unsigned long begin; + uchar *slice; }; #endif //IMAGEPACKET_H diff --git a/server.cpp b/server.cpp index fca6e35..2255d4a 100644 --- a/server.cpp +++ b/server.cpp @@ -1,20 +1,55 @@ #include -#include #include +#include +#include +#include +#include +#include +#include using namespace std; int main() { // TODO: read image data from socket instead of VideoCapture - cv::VideoCapture cap = cv::VideoCapture(0); - bool running = true; + // creating socket + int serverSocket = socket(AF_INET, SOCK_STREAM, 0); + + // specifying the address + sockaddr_in serverAddress; + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(8080); + serverAddress.sin_addr.s_addr = INADDR_ANY; + + // binding socket. + bind(serverSocket, (struct sockaddr*)&serverAddress, + sizeof(serverAddress)); + + // listening to the assigned socket + listen(serverSocket, 5); + + // accepting connection request + int clientSocket + = accept(serverSocket, nullptr, nullptr); + // TODO: handle multiple images cv::Mat image = cv::Mat::zeros(480, 640, CV_8UC3); + + // setup packet buffer + char buffer[IMAGEPACKET_SIZE] = { 0 }; + ImagePacket packet = ImagePacket(&image, 0); + + bool running = true; // TODO: make this asynchronous. probably do that in tandem with setting up networking while (running) { - cap.read(image); + // receive data + recv(clientSocket, buffer, sizeof(buffer), 0); + packet.deserialize(buffer); + cout << "received packet with index " << packet.getBegin() << endl; + packet.apply(&image); + imshow("image", image); running = cv::waitKey(30) != 27; } + close(serverSocket); return 0; -} +} \ No newline at end of file