Commit 2bd583cf authored by Florian Fischer's avatar Florian Fischer
Browse files

add initial client implementation

parent ad3888b2
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright © 2020 Florian Fischer
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <random>
#include <string>
#include "AsyncLibrary.hpp"
#include "Common.hpp"
#include "Fiber.hpp"
#include "Runtime.hpp"
#define BUF_MAX 4096
static const int DECIMAL = 10;
static const unsigned DEFAULT_CLIENTS = 10;
static const unsigned DEFAULT_MSG_LENGTH = 128;
static const unsigned DEFAULT_ITERATIONS = 1000;
static const int DEFAULT_PORT = 12345;
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
static const char DEFAULT_ADDRESS[] = "127.0.0.1";
static auto random_string(unsigned length) -> std::string {
std::mt19937 generator{std::random_device{}()};
std::uniform_int_distribution<int> distribution{'a', 'z'};
std::string rand_str(length, '\0');
for (auto& dis : rand_str) {
dis = distribution(generator);
}
return rand_str;
}
void client_func(int sockfd, unsigned iterations, unsigned msg_length) {
assert(msg_length < BUF_MAX);
// NOLINTNEXTLINE(modernize-avoid-c-arrays)
char buf[BUF_MAX];
for (size_t i = 0; i < iterations; ++i) {
const auto s = random_string(msg_length);
size_t bytes_send = 0;
while (bytes_send < s.length()) {
ssize_t new_bytes_send =
emper::io::send_and_wait(sockfd, s.c_str() + bytes_send, s.length() - bytes_send, 0);
if (unlikely(new_bytes_send == 0)) {
std::cerr << "socked closed by server" << std::endl;
return;
}
if (unlikely(new_bytes_send == -1)) {
perror("send failed");
return;
}
bytes_send += new_bytes_send;
}
int bytes_recv = emper::io::recv_and_wait(sockfd, buf, s.length(), MSG_WAITALL);
if (bytes_recv == 0) {
std::cerr << "socked closed by server" << std::endl;
return;
}
if (bytes_recv == -1) {
perror("recv failed");
return;
}
if (strncmp(s.c_str(), buf, s.length()) != 0) {
std::cerr << "unexpected string received from server" << std::endl;
}
shutdown(sockfd, SHUT_RDWR);
}
}
auto main(int argc, char* argv[]) -> int {
unsigned clients = DEFAULT_CLIENTS;
int port = DEFAULT_PORT;
char* addr = (char*)&DEFAULT_ADDRESS[0];
unsigned iterations = DEFAULT_ITERATIONS;
unsigned msg_length = DEFAULT_MSG_LENGTH;
if (argc > 1) {
iterations = (int)strtol(argv[1], nullptr, DECIMAL);
}
if (argc > 2) {
port = (int)strtol(argv[2], nullptr, DECIMAL);
}
if (argc > 3) {
addr = argv[3];
}
Runtime runtime;
for (unsigned i = 0; i < clients; ++i) {
Fiber* client_fiber = Fiber::from([&]() {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
DIE_MSG_ERRNO("client socket creation failed");
}
struct sockaddr_in server_addr;
// assign IP, PORT
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(addr);
server_addr.sin_port = htons(port);
if (emper::io::connect_and_wait(sockfd, reinterpret_cast<struct sockaddr*>(&server_addr),
sizeof(server_addr)) == -1) {
DIE_MSG_ERRNO("connect failed");
}
client_func(sockfd, iterations, msg_length);
});
runtime.schedule(*client_fiber);
}
runtime.waitUntilFinished();
}
configure_file(output: 'config.h', configuration: conf_data)
inc = include_directories('.')
cpp_exe = executable('emper-echo-client',
'emper-echo-client.cpp',
include_directories : [inc],
dependencies: dependencies)
cpp_exe = executable('emper-echo-server',
'emper-echo-server.cpp',
include_directories : [inc],
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment