# Лабораторна робота №4 Філіпенко Микита Володимирович
## 1. Постановка Задачі
Виконати завдання лабораторної роботи 1, використовуючи методи протоколу WebSocket
## 2. Теоретичні відомості
WebSocket - це протокол зв'язку між клієнтом і сервером, який дозволяє встановлювати двостороннє з'єднання і обмінюватися даними в реальному часі. Ось кілька теоретичних відомостей про WebSocket:
1. Запит і відповідь: WebSocket розпочинається як звичайний HTTP-запит від клієнта до сервера. У заголовку запиту клієнт вказує, що він бажає встановити WebSocket-з'єднання. Сервер, якщо підтримує WebSocket, відповідає спеціальним HTTP-відповідями, які ініціюють перехід до протоколу WebSocket.
2. Протокол WebSocket: Після успішної ініціалізації сервер і клієнт можуть обмінюватися даними у вигляді повідомлень. WebSocket використовує одне з'єднання для обидвох напрямків, що дозволяє зменшити накладні витрати порівняно з традиційними HTTP-запитами.
3. Безпека: WebSocket має вбудовану підтримку захищеного з'єднання за допомогою шифрування TLS/SSL. Це забезпечує конфіденційність та цілісність даних, які передаються через WebSocket.
4. Реальний час: Одним з основних призначень WebSocket є підтримка реального часу веб-додатків, таких як чати, онлайн-ігри, фінансові тікери тощо. Він дозволяє миттєво відправляти та отримувати дані без необхідності постійних запитів з боку клієнта.
5. Порівняння з HTTP: WebSocket відрізняється від HTTP у тому, що він підтримує постійне з'єднання між клієнтом і сервером, що дозволяє обмінюватися даними в обидва боки без необхідності постійно відкривати нові з'єднання для кожного запиту.
## 3. Результати
### 3.1 Для PAN

### 3.2 Для WAN (replit.com хостінг)

## 4. Інтерпретація результатів
### 4.1 Аналіз PAN таблиці:
* З загальної картини можна побачити, що для будь-якого розміру запиту та частоти значення RTT є дуже маленькими. (Особливо у порівнянні коли використовувався протокол HTTP).
### 4.2 Аналіз WAN таблиці:
* З WAN таблиці можна також побачити, що порівнюючи з HTTP протоколом результати є значно меншими. А також зі збільшенням частоти RTT приймає все менші значення.
### Висновки:
Дивлячись и порівнюючи результати, можна зробити висновки чому RTT у WebSocket менші аніж у HTTP:
1. Постійне з'єднання: WebSocket дозволяє підтримувати постійне з'єднання між клієнтом та сервером. Одного разу встановлене з'єднання може використовуватись для обміну даними без необхідності повторних з'єднань для кожного запиту, як у випадку HTTP.
2. Немає необхідності у заголовках запиту-відповіді: HTTP потребує передачі заголовків запиту та відповіді для кожного обміну даними. Це може займати додатковий час та об'єм даних на мережі. WebSocket, натомість, дозволяє простішу передачу даних без додаткового навантаження.
3. Менше рукостискань: У випадку HTTP, для кожного запиту та відповіді можуть вимагатись додаткові рукостискання (handshakes), такі як установлення TCP-з'єднання. У WebSocket, якщо з'єднання вже встановлено, це може зменшити кількість рукостискань та спростити обмін даними.
## 5. Висновок
У результаті цієї лабораторної роботи я створив клієнт-серверний додаток на JavaScript з використанням протоколу WebSocket для тестування часу подорожі запитів (RTT) у PAN та WAN. Я отримав дані про мінімальний, максимальний, медіанний та середній час RTT, а також характеристики каналу залежно від розміру та частоти запитів.
## Додаток
Посилання на replit - https://replit.com/join/kzdmbenpkt-nikitafilipenko
index.js файл
```javascript=1
const http = require("http"); // use http module
const socketio = require("socket.io"); // use socket.io module!
const express = require("express"); // use express module
const app = express(); // create instance of express
app.use(express.static("public")); // use "public" directory for static files
const server = http.Server(app); // create http server enriched by express functions
const io = socketio(server); // create instance of socketio over http server
app.get("/", (req, res) => {
res.sendFile(join(__dirname, "index.html"));
});
//// -------------------------------------------------------
io.on("connection", (socket) => {
//// --- when server recieves the "joined" message
socket.on(
"joined",
// send message to client
() => {
io.emit("joined");
},
);
//// --- when someone closes the tab
socket.on("disconnect", () => {
io.emit("leave");
});
//// --- when server recieves the "sendRequest" message
socket.on("requestSend", () => {
// Acknowledge receipt of the emit without sending data
let timeStamp = Date.now();
socket.emit("requestGet", timeStamp);
});
});
server.listen(3000, () => {
console.log("Server is listening in port 3000");
}); // run server on port 3000
```
client.js файл
```javascript=1
const socket = io(); // create new instance
//Масив для збереження даних
rtts = [];
const frequeincies = [1, 2, 4, 8, 16];
const requestSizes = [128, 256, 512, 1024, 2048];
const max_req_freq = 100;
let requestCount = 0;
let requestCountIndex = 0;
let frequencyIterator = 0;
let requestSizeIterator = 0;
let Timer;
let minRtt = 0;
let maxRtt = 0;
let meanRtt = 0;
let medianRtt = 0;
let stddevRtt = 0;
let skewnessRtt = 0;
//Функція для створення відповідного розміру даних за завданням лабораторної роботи
function createData(dataSize) {
return "a".repeat(dataSize);
}
//Функція для розрахунку мінімуму
function dataMin(data) {
return Math.min(...data);
}
//Функція для розрахунку максимуму
function dataMax(data) {
return Math.max(...data);
}
//Функція для розрахунку середнього
function dataMean(data) {
const sum = data.reduce((acc, val) => acc + val, 0);
return sum / data.length;
}
//Функція для розрахунку медіани
function dataMedian(data) {
data.sort((a, b) => a - b);
const middle = Math.floor(data.length / 2);
if (data.length % 2 === 0) {
// Якщо кількість елементів парна
return (data[middle - 1] + data[middle]) / 2;
} else {
// Якщо кількість елементів непарна
return data[middle];
}
}
//Функція для розрахунку стандартного квадратичного відхілення
function dataStandartDerivation(data) {
const variance = data.reduce((a, b) =>
a + Math.pow(b - dataMean(data), 2), 0) /
data.length;
return Math.sqrt(variance);
}
//Функція для розрахунку коефінценту асиметрії
function dataSkewness(data) {
const n = data.length;
meanRtt = dataMean(data);
const cubedDiffs = data.map((val) => (val - meanRtt) ** 3);
const sum = cubedDiffs.reduce((acc, val) => acc + val, 0);
const avgCubedDiff = sum / cubedDiffs.length;
std = dataStandartDerivation(data);
const skewness = avgCubedDiff / std ** 3;
return skewness * (n / ((n - 1) * (n - 2)));
}
function getMectrics(rtt) {
rtts.push(rtt);
minRtt = dataMin(rtts);
maxRtt = dataMax(rtts);
meanRtt = dataMean(rtts);
medianRtt = dataMedian(rtts);
stddevRtt = dataStandartDerivation(rtts);
skewnessRtt = dataSkewness(rtts);
console.log("Started function, iteration: ", frequencyIterator);
document.getElementById("checking").innerHTML =
"freq: " +
frequeincies[frequencyIterator] +
"\n" +
"rtt: " +
rtt +
"\n" +
"rtt_count: " +
rtts.length +
"\n" +
"min: " +
minRtt +
"\n" +
"max: " +
maxRtt +
"\n" +
"mean: " +
meanRtt +
"\n" +
"median: " +
medianRtt +
"\n" +
"stddev: " +
stddevRtt +
"\n" +
"skewness: " +
skewnessRtt +
"\n";
}
function sendRequest(dataSize) {
const data = createData(dataSize);
const startTime = Date.now();
/// --- when server recieves the "joined" message
socket.emit("requestSend", () => {
data: data;
});
/// --- when server recieves the "joined" message
socket.once("requestGet", (timeStamp) => {
const rtt = Date.now() - startTime; // Расчет RTT
getMectrics(rtt);
});
}
function setTableContents(frequency, requestSize) {
const tableInfo = document.querySelector("#tablebody");
const newTableRow = document.createElement("tr");
newTableRow.innerHTML = `
<td>${frequency}</td>
<td>${requestSize}</td>
<td>${max_req_freq}</td>
<td>${minRtt}</td>
<td>${maxRtt}</td>
<td>${meanRtt}</td>
<td>${medianRtt}</td>
<td>${stddevRtt}</td>
<td>${skewnessRtt}</td>
`;
tableInfo.append(newTableRow);
}
function main() {
console.log("Checking button event listner");
function sendRequestOnInterval() {
const currentFrequency = frequeincies[frequencyIterator];
const currentRequestSize = requestSizes[requestSizeIterator];
Timer = setInterval(
() => {
if (requestCount >= max_req_freq) {
clearInterval(Timer);
rtts = [];
requestCount = 0;
setTableContents(currentFrequency, currentRequestSize);
// После завершения запросов для текущего размера запроса,
// переходим к следующему размеру и продолжаем отправку запросов
requestSizeIterator++;
if (requestSizeIterator < requestSizes.length) {
// Если есть еще размеры запросов, отправляем запросы с новым размером
setTimeout(sendRequestOnInterval, 0);
} else {
frequencyIterator++;
if (frequencyIterator < frequeincies.length) {
requestSizeIterator = 0;
// Если есть еще частоты, отправляем запросы с новой частотой
setTimeout(sendRequestOnInterval, 0);
}
}
} else {
// Отправляем запрос с текущим размером
sendRequest(currentRequestSize);
requestCountIndex++;
requestCount++;
}
},
Math.floor(1000 / currentFrequency),
);
}
sendRequestOnInterval();
}
//// --- when server tells to this client that someone has opened the page
socket.on("joined", () => {
console.log("someone joined");
});
//// --- when server tells to this client that someone has closed the page
socket.on("leave", () => {
console.log("someone closed page");
});
socket.emit("joined"); // tell server that someone opened the page
socket.emit("sendRequest", () => {
console.log("request received by server");
});
document.getElementById("button").addEventListener("click", main);
```