diff options
| author | crupest <crupest@outlook.com> | 2021-05-27 15:13:46 +0800 | 
|---|---|---|
| committer | crupest <crupest@outlook.com> | 2021-05-27 15:13:46 +0800 | 
| commit | a1192a14c6a52e8ab77e1c84e38b65aa5e250bec (patch) | |
| tree | 50d2653f664a6aaf5593da6837b78294dc9715f5 | |
| parent | 6c0e4b64fa9967b2a2ef7dfb840cab3a8325f67e (diff) | |
| download | crupest-a1192a14c6a52e8ab77e1c84e38b65aa5e250bec.tar.gz crupest-a1192a14c6a52e8ab77e1c84e38b65aa5e250bec.tar.bz2 crupest-a1192a14c6a52e8ab77e1c84e38b65aa5e250bec.zip | |
import(life): Add computer network experiment.
| -rw-r--r-- | works/life/computer-network-experiment/.clangd | 2 | ||||
| -rw-r--r-- | works/life/computer-network-experiment/.gitignore | 2 | ||||
| -rw-r--r-- | works/life/computer-network-experiment/client.cpp | 66 | ||||
| -rw-r--r-- | works/life/computer-network-experiment/server.cpp | 132 | ||||
| -rw-r--r-- | works/life/main.cpp | 36 | 
5 files changed, 238 insertions, 0 deletions
| 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 <Windows.h>
 +#include <iostream>
 +#include <string>
 +#include <winsock.h>
 +
 +#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 <cstdlib>
 +#include <ios>
 +#include <iostream>
 +#include <mutex>
 +#include <optional>
 +#include <string>
 +#include <string_view>
 +#include <thread>
 +
 +#include <Windows.h>
 +#include <winsock.h>
 +
 +#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<int> 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<std::mutex> 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<std::mutex> guard(cout_mutex);
 +      std::cerr << "Failed to send!\n";
 +      closesocket(socket);
 +      break;
 +    }
 +
 +    byte_count_sent += byte_actually_sent;
 +  }
 +
 +  {
 +    std::lock_guard<std::mutex> 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<sockaddr *>(&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<sockaddr *>(&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();
 +  }
 +}
 diff --git a/works/life/main.cpp b/works/life/main.cpp new file mode 100644 index 0000000..efb5bff --- /dev/null +++ b/works/life/main.cpp @@ -0,0 +1,36 @@ +#include <WinSock2.h>
 +#include <Windows.h>
 +#include <cassert>
 +#include <iostream>
 +#include <iphlpapi.h>
 +#include <string>
 +
 +std::wstring ToString(const SOCKET_ADDRESS &addr) {
 +  DWORD buffer_length = 100;
 +  wchar_t buffer[100];
 +  auto error = WSAAddressToStringW(addr.lpSockaddr, addr.iSockaddrLength, NULL,
 +                                   buffer, &buffer_length);
 +  assert(error == 0);
 +  return std::wstring(buffer);
 +}
 +
 +int main() {
 +  WSADATA wsaData;
 +  int error = WSAStartup(MAKEWORD(2, 0), &wsaData);
 +  assert(error == 0);
 +
 +  ULONG buffer_size = 100000;
 +  PIP_ADAPTER_ADDRESSES_LH buffer =
 +      (PIP_ADAPTER_ADDRESSES_LH)malloc(buffer_size);
 +  ULONG error2 = GetAdaptersAddresses(
 +      AF_INET,
 +      GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_INCLUDE_GATEWAYS |
 +          GAA_FLAG_INCLUDE_ALL_INTERFACES | GAA_FLAG_SKIP_MULTICAST,
 +      NULL, buffer, &buffer_size);
 +  assert(error2 == ERROR_SUCCESS);
 +
 +  std::wcout << ToString(buffer->FirstPrefix->Address) << L"\n";
 +  std::wcout << buffer->FirstGatewayAddress << L"\n";
 +
 +  return 0;
 +}
 | 
