server upd
added python client
This commit is contained in:
parent
2f182e119c
commit
4819674833
4
.gitignore
vendored
4
.gitignore
vendored
@ -11,4 +11,6 @@ install_strip_local_manifest.txt
|
|||||||
install_strip_local_manifest.txt
|
install_strip_local_manifest.txt
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
my_own_redis
|
|
||||||
|
.venv/
|
||||||
|
my_own_redis
|
||||||
|
|||||||
1
.python-version
Normal file
1
.python-version
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.13
|
||||||
@ -3,14 +3,15 @@ cmake_minimum_required(VERSION 3.10)
|
|||||||
project(MyOwnRedis)
|
project(MyOwnRedis)
|
||||||
|
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDART 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_REQUIRED ON)
|
set(CMAKE_CXX_REQUIRED_FLAGS -Wall -Wextra -Werror)
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/utils.cpp
|
src/utils.cpp
|
||||||
src/config.cpp
|
src/config.cpp
|
||||||
src/server.cpp
|
src/server.cpp
|
||||||
|
src/net_util.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(my_own_redis ${SOURCES})
|
add_executable(my_own_redis ${SOURCES})
|
||||||
|
|||||||
50
client.py
Normal file
50
client.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
def recv_exact(sock: socket.socket, n: int) -> bytes:
|
||||||
|
data = b''
|
||||||
|
while len(data) < n:
|
||||||
|
chunk = sock.recv(n - len(data))
|
||||||
|
if len(chunk) == 0:
|
||||||
|
raise ConnectionError('EOF from server')
|
||||||
|
data += chunk
|
||||||
|
return data
|
||||||
|
|
||||||
|
def send_frame(sock: socket.socket, payload: bytes) -> None:
|
||||||
|
header = struct.pack('!I', len(payload))
|
||||||
|
sock.sendall(header + payload)
|
||||||
|
|
||||||
|
def recv_frame(sock: socket.socket) -> bytes:
|
||||||
|
header = recv_exact(sock, 4)
|
||||||
|
(length,) = struct.unpack('!I', header)
|
||||||
|
if length > 10_000_000:
|
||||||
|
raise ValueError('Message length is too long')
|
||||||
|
return recv_exact(sock, length)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='NOT(Redis) client')
|
||||||
|
parser.add_argument('-H', '--host', type=str, required=False, default='127.0.0.1', help='Server host')
|
||||||
|
parser.add_argument('-P', '--port', type=int, required=False, default=6379, help='Server port')
|
||||||
|
parser.add_argument('-M', '--message', type=str, required=False, default='hello', help='Message to send')
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
with socket.create_connection((args.host, args.port)) as sock:
|
||||||
|
send_frame(sock, args.message.encode())
|
||||||
|
response = recv_frame(sock)
|
||||||
|
print('Message sent:', args.message)
|
||||||
|
print('Server says:', response.decode("utf-8", errors='replace'))
|
||||||
|
except ConnectionRefusedError as e:
|
||||||
|
print('Connection refused by server:', e)
|
||||||
|
exit(1)
|
||||||
|
except ConnectionError as e:
|
||||||
|
print('Failed to connect to server:', e)
|
||||||
|
exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print('Unexpected error:', e)
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
10
pyproject.toml
Normal file
10
pyproject.toml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[project]
|
||||||
|
name = "own-redis-client"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Fuck C++ for client I swear bruh"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.13"
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
client = "python client.py"
|
||||||
5
src/constants.hpp
Normal file
5
src/constants.hpp
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
const uint32_t k_max_message_size = 4096;
|
||||||
37
src/net_util.cpp
Normal file
37
src/net_util.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "net_util.hpp"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
int32_t read_full(int connectionfd, void* buf, size_t len) {
|
||||||
|
auto buffer = static_cast<char*>(buf);
|
||||||
|
while (len > 0) {
|
||||||
|
ssize_t rv = ::read(connectionfd, buffer, len);
|
||||||
|
if (rv == 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (rv < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buffer += rv;
|
||||||
|
len -= static_cast<size_t>(rv);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t write_all(int connectionfd, const void* buf, size_t len) {
|
||||||
|
auto* buffer = static_cast<const char*>(buf);
|
||||||
|
while (len > 0) {
|
||||||
|
ssize_t rv = ::write(connectionfd, buffer, len);
|
||||||
|
if (rv <= 0) {
|
||||||
|
if (rv < 0 && errno == EINTR) continue;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
buffer += rv;
|
||||||
|
len -= static_cast<size_t>(rv);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
7
src/net_util.hpp
Normal file
7
src/net_util.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int32_t read_full(int connectionfd, void* buf, size_t len);
|
||||||
|
int32_t write_all(int connectionfd, const void* buf, size_t len);
|
||||||
@ -1,9 +1,20 @@
|
|||||||
#include "server.hpp"
|
#include <assert.h>
|
||||||
#include <iostream>
|
#include <stdint.h>
|
||||||
#include <sys/socket.h>
|
#include <stdlib.h>
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "server.hpp"
|
||||||
|
#include "net_util.hpp"
|
||||||
|
#include "constants.hpp"
|
||||||
|
#include "utils.hpp"
|
||||||
|
|
||||||
|
|
||||||
Server::Server(const Config& config)
|
Server::Server(const Config& config)
|
||||||
: address(config.get_address()), port(config.get_port()), sockfd(-1) {
|
: address(config.get_address()), port(config.get_port()), sockfd(-1) {
|
||||||
@ -43,18 +54,41 @@ void Server::setup() {
|
|||||||
std::cout << "Server started on " << address << ":" << port << "\n";
|
std::cout << "Server started on " << address << ":" << port << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::handle_connection(int connectionfd) {
|
int32_t Server::handle_connection(int connectionfd) {
|
||||||
char rbuf[64] = {};
|
std::cout << "Waiting for data from " << connectionfd << "\n";
|
||||||
ssize_t n = read(connectionfd, rbuf, sizeof(rbuf) - 1);
|
|
||||||
if (n < 0) {
|
uint32_t len_net = 0;
|
||||||
std::cerr << "Error reading client packet\n";
|
errno = 0;
|
||||||
return;
|
if (read_full(connectionfd, &len_net, sizeof(len_net)) != 0) {
|
||||||
|
print_error(errno == 0 ? "EOF from client" : "Error reading length");
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
std::cout << "Client says: " << std::string(rbuf, n) << "\n";
|
|
||||||
ssize_t written = write(connectionfd, "Hello, client!\n", 14);
|
uint32_t len = ntohl(len_net);
|
||||||
if (written < 0) {
|
|
||||||
std::cerr << "Error writing to client\n";
|
if (len > k_max_message_size) {
|
||||||
|
print_error("Message length is too long");
|
||||||
|
std::cerr << len << " > " << k_max_message_size << "\n";
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string message(len, '\0');
|
||||||
|
if (len > 0) {
|
||||||
|
if (read_full(connectionfd, message.data(), len) != 0) {
|
||||||
|
print_error("Error reading payload");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Client says: " << message << "\n";
|
||||||
|
|
||||||
|
const std::string reply = "world";
|
||||||
|
uint32_t reply_len_net = htonl(static_cast<uint32_t>(reply.size()));
|
||||||
|
|
||||||
|
if (write_all(connectionfd, &reply_len_net, sizeof(reply_len_net)) != 0) return -1;
|
||||||
|
if (write_all(connectionfd, reply.data(), reply.size()) != 0) return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Server::run() {
|
void Server::run() {
|
||||||
@ -67,7 +101,14 @@ void Server::run() {
|
|||||||
if (connectionfd < 0) {
|
if (connectionfd < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
handle_connection(connectionfd);
|
std::cout << "Accepted connection from " << connectionfd << "\n";
|
||||||
|
while (true) {
|
||||||
|
int32_t err = handle_connection(connectionfd);
|
||||||
|
if (err) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << "Closing connection from " << connectionfd << "\n";
|
||||||
close(connectionfd);
|
close(connectionfd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <stdint.h>
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
|
|
||||||
class Server {
|
class Server {
|
||||||
@ -15,6 +16,6 @@ private:
|
|||||||
std::string address;
|
std::string address;
|
||||||
int port;
|
int port;
|
||||||
|
|
||||||
void handle_connection(int connectionfd);
|
int32_t handle_connection(int connectionfd);
|
||||||
void setup();
|
void setup();
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,3 +7,7 @@ void stop_program(int signum) {
|
|||||||
std::cout << "Exiting program...\n";
|
std::cout << "Exiting program...\n";
|
||||||
exit(signum);
|
exit(signum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_error(const std::string& msg) {
|
||||||
|
std::cerr << msg << ": " << std::strerror(errno) << "\n";
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
void stop_program(int signum);
|
void stop_program(int signum);
|
||||||
|
void print_error(const std::string& msg);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user