# **Лабораторна робота №2**
[TOC]
## Завдання до лаборатної роботи №2
1. Зробити клієнт-серверний додаток на мові javascript, який повинен запускатися в локальній мережі (localhost) та у глобальній мережі (glitch.com, replit.com), на рівні протоколу HTTP, використовуючи методи
I) GET
II) POST,
Додаток повинен тестувати часи подорожі та обробки матриць з числами типу double. Матриці повинні залежно від запиту оброблятися на сервері по-різному:
a) сервер повинен обчислити за вхідною матрицею матрицю зі зверненими елементами
b) сервер повинен обчислити за вхідною матрицею звернену матрицю
2. Перевірити роботу програми для розмірів матриць 256x256, 512x512, 1024x1024, 2048x2048, 4096x4096, 8192x8192
3. Програма має оцінити такі параметри каналу як
*пряму та зворотню затримки
передачі між термінальними вузлами з'єднання,
пряму та зворотню пропускну здатності каналу (Bandwidth=B),
пряму та зворотню затримки передавання в каналі– transmission delay
пряму та зворотню відносну затримку каналу
пряму та зворотню ефективність каналу*
4. Програма повинна передбачати
*час передачі даних на сервер
час обробки даних на сервері
час передачі оброблених даних із сервера на клієнт
загальний сумарний час та порівнювати його з реальним часом отримання результату після початку запиту клієнта до сервера.*
5. Результати представити у вигляді таблиць
## Рішення
Створюємо сервер на https://replit.com/
Створимо index.html - HTML-сторінка, з таблицею resTable для результатів.
```html=
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Lab2</title>
</head>
<style>
table, th, td {
border: 2px solid blue;
border-collapse: collapse;
}
th, td {
padding: 10px;
}
</style>
<body>
<h1>Lab 2</h1>
<h2>Invert Elemnts</h2>
<div id="test"></div>
<table id="invert-elements">
<tr>
<th>Matrix size</th>
<th>Request size Mb</th>
<th>Delta ms</th>
<th>Relative delay</th>
<th>Channel efficiency</th>
<th>Send data to server time (ms)</th>
<th>Processing time on server (ms)</th>
<th>Receive data from server time (ms)</th>
<th>Bandwidth (Bitps)</th>
<th>Calculated total time (ms)</th>
<th>Real total time (ms)</th>
</tr>
</table>
<h2>Invert Matrix</h2>
<table id="invert-matrix">
<tr>
<th>Matrix size</th>
<th>Request size Mb</th>
<th>Delta ms</th>
<th>Relative delay</th>
<th>Channel efficiency</th>
<th>Send data to server time (ms)</th>
<th>Processing time on server (ms)</th>
<th>Receive data from server time (ms)</th>
<th>Bandwidth (Bitps)</th>
<th>Calculated total time (ms)</th>
<th>Real total time (ms)</th>
</tr>
</table>
<script src="script.js"></script>
</body>
</html>
```
Код серверу який буде оброблювати GET запрос для відобрадженя коду HTML і запуску script.js функції яка запускає запити і оброблює POST запрос зі url = \test для обробки вхідной матриці: invert-elements - обчислити за вхідною матрицею матрицю зі зверненими елементами, invert-matrix - обчислити за вхідною матрицею звернену матрицю:
```javascript=
const http = require("http");
const fs = require("fs");
const path = require("path");
const math = require('mathjs');
const PORT = 3000;
const server = http.createServer((req, res) => {
if (req.method === "GET" ) {
let filePath = req.url === "/" ? "index.html" : req.url;
let extname = path.extname(filePath);
let contentType = extname === ".js" ? "application/javascript" : "text/html";
fs.readFile(path.join(__dirname, filePath),
(err, data) => {
if (err) {
res.writeHead(404, { "Content-Type": "text/plain" });
res.end("Not Found");
} else {
res.writeHead(200, { "Content-Type": contentType });
res.end(data);
}
});
} else if (req.method === "POST" && req.url === "/test") {
let body = '';
req.on('data', chunk => { body += chunk; });
req.on('end',
() => {
try {
let requestData = JSON.parse(body);
const { matrix, operation } = requestData;
const startProcessing = Date.now();
let result;
if (operation === "invert-elements") {
result = matrix.map(row => row.map(x => 1 / x));
} else if (operation === "invert-matrix") {
result = math.inv(matrix);
} else {
throw new Error("Invalid operation");
}
const endProcessing = Date.now();
const processingTime = endProcessing - startProcessing;
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ result, processingTimeMs: processingTime }));
} catch (error) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: error.message }));
}
});
} else if (req.method === "POST" && req.url === "/ping") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify("pong"));
}
else {
res.writeHead(404, { "Content-Type": "text/plain" });
res.end("Not Found");
}
});
server.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}/`);
});
```
та script.js для запуску логіки:
```javascript=
const matrixSizes = [256, 512, 1024, 2048, 4096];
const operations = ['invert-elements', 'invert-matrix'];
(async function start() {
for (let size of matrixSizes) {
for (let operation of operations) {
await process(operation, size);
}
}
})();
async function process(operation, matrixSize) {
const matrix = generateMatrix(matrixSize);
const bodyData = JSON.stringify({matrix, operation})
const startTotal = performance.now();
const startSend = performance.now();
const response = await fetch('/test', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: bodyData
});
const endSend = performance.now();
const startReceive = performance.now();
const data = await response.json();
const endReceive = performance.now();
const transfer_time = endSend - startSend - data.processingTimeMs;
const endTotal = performance.now();
const sendTime = endSend - startSend;
const receiveResponseTime = endReceive - startReceive;
const totalTime = endTotal - startTotal;
await calculateAndShow(operation, data, bodyData, matrixSize, transfer_time, totalTime, sendTime, receiveResponseTime);
}
async function calculateAndShow(operation, data, bodyData, matrixSize, transfer_time, totalTime, sendTime, receiveResponseTime) {
const delta = await calculateDelta();
const tau = transfer_time;
const totalBits = getJsonSizeInBits(bodyData);
const bandwidthBps = (totalBits / tau).toFixed(2);
const r = (delta / tau).toFixed(3);
const eta = (1 / (1 + 2 * r)).toFixed(2);
const calculateTime = data.processingTimeMs;
const T = (tau + 2 * delta + calculateTime).toFixed(3);
const output = `
<tr>
<td>${matrixSize}</td>
<td>${getJsonSizeInMB(bodyData).toFixed(2)} Mb</td>
<td>${delta.toFixed(3)}</td>
<td>${r}</td>
<td>${tau.toFixed(2)}</td>
<td>${calculateTime.toFixed(2)}</td>
<td>${(receiveResponseTime).toFixed(2)}</td>
<td>${T}</td>
<td>${(totalTime).toFixed(2)}</td>
<td>${bandwidthBps}</td>
<td>${eta}</td>
</tr>
`;
document.getElementById(operation).innerHTML += output;
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function generateMatrix(size) {
const matrix = [];
for (let i = 0; i < size; i++) {
const row = [];
for (let j = 0; j < size; j++) {
row.push(Math.random() * 100 + 1);
}
matrix.push(row);
}
return matrix;
}
function getJsonSizeInMB(json) {
const jsonString = JSON.stringify(json);
// Получаем длину в байтах (UTF-8)
const byteSize = new TextEncoder().encode(jsonString).length;
const sizeInMB = byteSize / (1024 * 1024); // байты в мегабайты
return sizeInMB;
}
function getJsonSizeInBits(json) {
const jsonString = JSON.stringify(json);
const byteSize = new TextEncoder().encode(jsonString).length;
const sizeInBits = byteSize * 8; // 1 байт = 8 бит
return sizeInBits;
}
async function calculateDelta() {
const attempts = 10;
let totalDelta = 0;
for (let i = 0; i < attempts; i++) {
const start = performance.now();
await fetch('/ping', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify("ping")
});
const end = performance.now();
const rtt = end - start;
totalDelta += rtt / 2;
}
return totalDelta / attempts;
}
```
## Результати запиту
Запуску сервера локально:

Запуску серверу в replit.com:

Запуску серверу в replit.com через мобільний інтернет:

## Висновок
Висновнок роботи програми для 2 різних результатів:
Час обробки (To) стрімко зростає при збільшенні розміру матриці, що свідчить про складність обчислень (особливо для оберненої матриці).
Пропускна здатність каналу (B) зростає з більшим об'ємом даних, що свідчить про кращу оптимізацію використання каналу при більшому навантаженні.
Ефективність каналу (η) трохи зростає із збільшенням розміру матриці, тобто канал працює ефективніше при передачі великих обсягів даних.
RTT може бути непостійним і залежати від зовнішніх факторів мережі (можливо фонові процеси або завантаження мережі).
Відносна затримка r залишається стабільною — змінюється лише навантаження.