From a1192a14c6a52e8ab77e1c84e38b65aa5e250bec Mon Sep 17 00:00:00 2001 From: crupest Date: Thu, 27 May 2021 15:13:46 +0800 Subject: import(life): Add computer network experiment. --- works/life/computer-network-experiment/.clangd | 2 + works/life/computer-network-experiment/.gitignore | 2 + works/life/computer-network-experiment/client.cpp | 66 +++++++++++ works/life/computer-network-experiment/server.cpp | 132 ++++++++++++++++++++++ 4 files changed, 202 insertions(+) create mode 100644 works/life/computer-network-experiment/.clangd create mode 100644 works/life/computer-network-experiment/.gitignore create mode 100644 works/life/computer-network-experiment/client.cpp create mode 100644 works/life/computer-network-experiment/server.cpp (limited to 'works/life/computer-network-experiment') diff --git a/works/life/computer-network-experiment/.clangd b/works/life/computer-network-experiment/.clangd new file mode 100644 index 0000000..c28ae22 --- /dev/null +++ b/works/life/computer-network-experiment/.clangd @@ -0,0 +1,2 @@ +CompileFlags: + Add: [-std=c++17] diff --git a/works/life/computer-network-experiment/.gitignore b/works/life/computer-network-experiment/.gitignore new file mode 100644 index 0000000..43561d4 --- /dev/null +++ b/works/life/computer-network-experiment/.gitignore @@ -0,0 +1,2 @@ +*.exe +*.pdb diff --git a/works/life/computer-network-experiment/client.cpp b/works/life/computer-network-experiment/client.cpp new file mode 100644 index 0000000..926ece6 --- /dev/null +++ b/works/life/computer-network-experiment/client.cpp @@ -0,0 +1,66 @@ +/** Created by crupest. + * This is the client program. + */ + +#include +#include +#include +#include + +#pragma comment(lib, "ws2_32.lib") + +const auto connect_address = "127.0.0.1"; // control connect address +const u_short port = 1234; // control connect port + +int main() { + WSADATA wsa_data; + + if (WSAStartup(MAKEWORD(2, 2), &wsa_data)) // initialize wsa + { + std::cerr << "WSA start up error!\n"; + WSACleanup(); + return 1; + } + + int client_socket; + + if ((client_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + std::cerr << "Failed to create socket!\n"; + WSACleanup(); + return 1; + } + + sockaddr_in server_address; + + server_address.sin_family = AF_INET; + server_address.sin_port = htons(port); + server_address.sin_addr.s_addr = inet_addr(connect_address); + memset(&(server_address.sin_zero), 0, sizeof(server_address.sin_zero)); + + if (connect(client_socket, (sockaddr *)&server_address, sizeof(sockaddr)) == + SOCKET_ERROR) { + std::cerr << "Failed to connect!"; + WSACleanup(); + return 1; + } + + const int buffer_size = 100; + char * buffer = new char[buffer_size]; + + int received_number = recv(client_socket, buffer, buffer_size, 0); + + if (received_number == -1) { + std::cerr << "Failed to recv."; + WSACleanup(); + return 1; + } + + std::string s(buffer, received_number); + + std::cout << "Received message:\n" << s; + + closesocket(client_socket); + WSACleanup(); + + return 0; +} diff --git a/works/life/computer-network-experiment/server.cpp b/works/life/computer-network-experiment/server.cpp new file mode 100644 index 0000000..1b196a9 --- /dev/null +++ b/works/life/computer-network-experiment/server.cpp @@ -0,0 +1,132 @@ +/** Created by crupest. + * This is the server program. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#pragma comment(lib, "Ws2_32.lib") + +const auto bind_address = "127.0.0.1"; // control bind address +const u_short port = 1234; // control bind port + +// As far as I know, cout is not thread safe. So we need a lock. But this might +// not be the best solution. We can use a queue instead to avoid block. +std::mutex cout_mutex; + +[[noreturn]] void +PrintErrorMessageAndExit(std::wstring_view message, + std::optional error_code = std::nullopt) { + std::wcerr << message << L'\n'; + + if (error_code) { + std::cerr << L"Error code is " << std::hex << *error_code << L'\n'; + wchar_t buffer[500]; + if (!FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_ARGUMENT_ARRAY | + FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, *error_code, 0, buffer, 500, nullptr)) { + std::wcerr << L"Failed to format error message.\n"; + } else { + std::wcerr << buffer << L'\n'; + } + } + + WSACleanup(); + + std::exit(1); +} + +void ResponseThreadProc(int socket, sockaddr_in address) { + auto address_string = inet_ntoa(address.sin_addr); + { + std::lock_guard guard(cout_mutex); + std::cout << "Connected to " << address_string << "!\n"; + } + + const std::string_view buffer = "Love you!!! By crupest!"; + + const int total_byte_count = buffer.size(); + int byte_count_sent = 0; + int retry_count = 0; + + while (true) { + // Now we have sent all data. + if (byte_count_sent == total_byte_count) + break; + + auto byte_actually_sent = send(socket, buffer.data() + byte_count_sent, + buffer.size() - byte_count_sent, 0); + + // send failed + if (byte_actually_sent == SOCKET_ERROR) { + std::lock_guard guard(cout_mutex); + std::cerr << "Failed to send!\n"; + closesocket(socket); + break; + } + + byte_count_sent += byte_actually_sent; + } + + { + std::lock_guard guard(cout_mutex); + std::cout << "Succeeded to send message to " << address_string << "!\n"; + } +} + +int main() { + WSADATA wsa_data; + + if (WSAStartup(MAKEWORD(2, 2), &wsa_data)) { // initialize wsa + PrintErrorMessageAndExit(L"Failed to initialize wsa.", WSAGetLastError()); + } + + int server_socket; + + if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + PrintErrorMessageAndExit(L"Failed to create socket.", WSAGetLastError()); + } + + sockaddr_in server_address; + + server_address.sin_family = AF_INET; + server_address.sin_port = htons(port); + server_address.sin_addr.s_addr = inet_addr(bind_address); + memset(&(server_address.sin_zero), 0, sizeof(server_address.sin_zero)); + + if (bind(server_socket, reinterpret_cast(&server_address), + sizeof(sockaddr_in)) == SOCKET_ERROR) { + PrintErrorMessageAndExit(L"Failed to bind.", WSAGetLastError()); + } + + if (listen(server_socket, SOMAXCONN) == SOCKET_ERROR) { + PrintErrorMessageAndExit(L"Failed to listen.", WSAGetLastError()); + } + + while (true) { + sockaddr_in client_address; + int client_socket; + int sin_size = sizeof(sockaddr_in); + client_socket = + accept(server_socket, reinterpret_cast(&client_address), + &sin_size); + + if (client_socket == INVALID_SOCKET) { + PrintErrorMessageAndExit(L"Failed to accecpt", WSAGetLastError()); + } + + std::thread response_thread(ResponseThreadProc, client_socket, + client_address); + response_thread.detach(); + } +} -- cgit v1.2.3