From 2a138d0c81c74578c4923414cd8f99838ab7dce2 Mon Sep 17 00:00:00 2001 From: VaclavT Date: Sun, 19 Dec 2021 13:35:19 +0100 Subject: [PATCH] improvements in networking code --- clib/tcpnet.cpp | 86 +++++++++++++++++++++++++++++++------------------ clib/tcpnet.h | 10 +++--- 2 files changed, 60 insertions(+), 36 deletions(-) diff --git a/clib/tcpnet.cpp b/clib/tcpnet.cpp index aaefcbf..64c9c9f 100644 --- a/clib/tcpnet.cpp +++ b/clib/tcpnet.cpp @@ -1,18 +1,17 @@ -#include -#include +#include +#include #include -#include -#include +#include #include #include #include +#include #include "tcpnet.h" -#define TCPNET_BUFFER_SIZE 131072 - +#define TCPNET_BUFFER_SIZE 16384 void error(const char *msg) { @@ -21,23 +20,21 @@ void error(const char *msg) { } // TODO do it as RAII -TcpNet::TcpNet() {} +TcpNet::TcpNet() = default; -int TcpNet::server(int portno, std::function(std::string)> process_request) const { +int TcpNet::server(int portno, const std::function(std::string)>& process_request) const { int sockfd, newsockfd; socklen_t clilen; - char buffer[TCPNET_BUFFER_SIZE]; struct sockaddr_in serv_addr, cli_addr; - int n; sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); - bzero((char *) &serv_addr, sizeof(serv_addr)); + memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); @@ -65,19 +62,17 @@ int TcpNet::server(int portno, std::function(std::s error("ERROR on accept"); while (true) { - bzero(buffer,TCPNET_BUFFER_SIZE); - n = read(newsockfd,buffer,TCPNET_BUFFER_SIZE - 1); - if (n == 0) break; // nothing to read from client anymore - if (n < 0) error("ERROR reading from socket"); + std::string request = read_from_socket(newsockfd); + if (request.empty()) break; - std::string request{buffer}; std::pair response = process_request(request); shutdown = response.first; std::string response_str = response.second; - n = write(newsockfd, response_str.c_str(), response_str.size()); - if (n < 0) + auto response_len = response_str.size(); + auto n = write(newsockfd, response_str.c_str(), response_len); + if (n < 0 || response_len != n) error("ERROR writing to socket"); requests_processed++; @@ -93,24 +88,22 @@ int TcpNet::server(int portno, std::function(std::s std::vector TcpNet::client(const std::string &address, int portno, const std::vector &requests) const { - int sockfd, n; + int sockfd; struct sockaddr_in serv_addr; struct hostent *server; std::vector responses; - char buffer[TCPNET_BUFFER_SIZE]; - sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) error("ERROR opening socket"); server = gethostbyname(address.c_str()); if (server == NULL) { - fprintf(stderr,"ERROR, no such host\n"); + fprintf(stderr, "ERROR, no such host\n"); exit(0); } - bzero((char *) &serv_addr, sizeof(serv_addr)); + memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); serv_addr.sin_port = htons(portno); @@ -121,16 +114,10 @@ std::vector TcpNet::client(const std::string &address, int portno, responses.reserve(requests.size()); for(const auto &req : requests) { - n = write(sockfd, req.c_str(), strlen(req.c_str())); - if (n < 0) - error("ERROR writing to socket"); - - bzero(buffer, TCPNET_BUFFER_SIZE); - n = read(sockfd,buffer, TCPNET_BUFFER_SIZE - 1); - if (n < 0) - error("ERROR reading from socket"); + write_to_socket(sockfd, req); - responses.push_back(std::string(buffer)); + std::string response = read_from_socket(sockfd); + responses.push_back(response); } close(sockfd); @@ -144,4 +131,39 @@ std::string TcpNet::client(const std::string &address, int portno, const std::st auto response = client(address, portno, c); return response[0]; +} + +std::string TcpNet::read_from_socket(int sockfd) { + char buffer[TCPNET_BUFFER_SIZE]; + std::string request; + + long n; + do { + memset(buffer, 0, TCPNET_BUFFER_SIZE); + n = read(sockfd, buffer, TCPNET_BUFFER_SIZE - 1); + if (n == 0) break; // nothing to read from client anymore + if (n < 0) { + if (errno == ECONNRESET) break; // connection reset by peer + + std::string err_desc{"ERROR reading from socket "}; + err_desc.append(strerror(errno)); + error(err_desc.c_str()); + } + + std::string part{buffer}; + request.append(part); + } while (n == TCPNET_BUFFER_SIZE - 1); // TODO what if data exactly of this size + + return request; +} + +void TcpNet::write_to_socket(int sockfd, const std::string &str) { + const char * buffer = str.c_str(); + int pos = 0; + long n; + do { + n = write(sockfd, buffer + pos, (int)(str.length() - pos)); + if (n < 0) + error("ERROR writing to socket"); + } while (pos + n < str.length()); } \ No newline at end of file diff --git a/clib/tcpnet.h b/clib/tcpnet.h index b994dce..4adab26 100644 --- a/clib/tcpnet.h +++ b/clib/tcpnet.h @@ -10,11 +10,13 @@ public: TcpNet(); // starts listening on port - int server(int port, std::function(std::string)> process_request) const; + int server(int port, const std::function(std::string)>& process_request) const; // writes request to server on address:port and returns response - std::string client(const std::string &address, int portno, const std::string &request) const; - - std::vector client(const std::string &address, int portno, const std::vector &requests) const; + [[nodiscard]] std::string client(const std::string &address, int portno, const std::string &request) const; + [[nodiscard]] std::vector client(const std::string &address, int portno, const std::vector &requests) const; +private: + static std::string read_from_socket(int sockfd) ; + static void write_to_socket(int sockfd, const std::string &str) ; };