TCP vs. UDP
Protokół TCP i UDP są fundamentami działania internetu, umożliwiając przesyłanie różnych typów danych z jednego źródła sieciowego do miejsca docelowego. TCP jest bardziej niezawodny, podczas gdy UDP stawia na szybkość i wydajność.
TCP stanowi jeden z kluczowych filarów globalnego internetu. Programy komunikacyjne oraz urządzenia komputerowe wykorzystują TCP do wymiany wiadomości w sieci. Zadaniem tego protokołu jest przenoszenie pakietów przez Internet i zapewnienie skutecznego dostarczania wiadomości oraz danych między sieciami.
Zanim możliwe będzie przesłanie jakichkolwiek danych, klient i serwer muszą nawiązać połączenie. Serwer musi aktywnie nasłuchiwać żądań klienta za każdym razem, gdy nawiązywane jest połączenie. TCP, jako protokół oparty na połączeniu, tworzy i utrzymuje połączenie pomiędzy odbiorcą a nadawcą w czasie przesyłania danych. Dzięki temu wszelkie informacje przesyłane przez Internet są gwarantowane do dotarcia bez zmian.
Z tego powodu TCP należy do najczęściej używanych protokołów sieciowych.
Oto niektóre z najważniejszych cech TCP:
- Klient potwierdza odbiór danych od serwera.
- Po upływie określonego czasu, w przypadku braku potwierdzenia, serwer podejmuje próbę ponownej transmisji danych.
- W przypadku przeciążonej sieci TCP opóźnia przesyłanie danych.
- Wykorzystuje trójstopniowe uzgadnianie (three-way handshake) w celu wykrycia błędów transmisji.
TCP to protokół zorientowany połączeniowo, który korzysta z uzgadniania trójetapowego, aby nawiązać połączenie. Działa poprzez wymianę następujących pakietów:
Pakiet SYN (Synchronizuj): klient inicjuje połączenie, wysyłając pakiet SYN do serwera. Pakiet ten zawiera początkowy numer sekwencyjny klienta.
Pakiet SYN-ACK (Synchronizuj-Potwierdź): po otrzymaniu pakietu SYN serwer odpowiada pakietem SYN-ACK. Dany pakiet potwierdza SYN klienta i zawiera początkowy numer sekwencyjny serwera.
Pakiet ACK (Potwierdź): wreszcie klient wysyła do serwera pakiet ACK potwierdzający SYN-ACK serwera. Połączenie zostaje ustanowione i klient oraz serwer mogą rozpocząć wymianę danych.
Jednak mimo że TCP jest z natury protokołem niezawodnym, mechanizmy te wiążą się z większym narzutem danych. Oznacza to, że TCP zużywa znacznie więcej dostępnej przepustowości systemu. Większość aplikacji internetowych wykorzystuje zatem protokół datagramów użytkownika (UDP) w połączeniu z TCP, aby zminimalizować ten problem.
Protokół UDP to zorientowany na komunikaty protokół komunikacyjny, który umożliwia urządzeniom komputerowym i aplikacjom przesyłanie danych przez sieć bez weryfikacji ich dostarczenia, co czyni go najlepiej przystosowanym do komunikacji w czasie rzeczywistym oraz systemów nadawczych (broadcastowych).
Podobnie jak w przypadku TCP, celem UDP jest wysyłanie i odbieranie wiadomości. Tym, co wyróżnia UDP, jest to, że nie jest oparty na połączeniu. W tym kontekście „bezpołączeniowy” oznacza, że przed rozpoczęciem komunikacji nie jest nawiązywane żadne połączenie.
Co więcej, UDP nie zapewnia dostarczenia pakietów danych od serwera. Często określa się go mianem protokołu „wyślij i zapomnij” (ang. fire-and-forget), ponieważ nie przejmuje się tym, czy klient rzeczywiście otrzymał dane.
W większości przypadków UDP jest szybszy od TCP, ponieważ nie zapewnia dostarczalności pakietów, tak jak robi to TCP.
Protokół UDP nie nadaje się do wysyłania poczty elektronicznej, przeglądania stron internetowych ani pobierania plików. Jednak jest preferowany głównie w zastosowaniach czasu rzeczywistego, takich jak transmisje na żywo (broadcasting) lub przesyłanie wielu strumieni danych w sieciach wielozadaniowych.
Kluczowe cechy UDP:
- Przystosowany do aplikacji o dużym zapotrzebowaniu na przepustowość, które tolerują utratę pakietów.
- Mniejsze opóźnienia w transmisji danych.
- Umożliwia wysyłanie dużej liczby pakietów jednocześnie.
- Istnieje ryzyko utraty części danych.
TCP: odpowiedni do aktywności, które wymagają stabilnego połączenia, takich jak przeglądanie Internetu (HTTP, HTTPS), sprawdzanie skrzynki e-mail (SMTP, IMAP/POP), pobieranie i przesyłanie (FTP) oraz zdalny dostęp do komputera za pomocą secure shell (SSH)
UDP: odpowiedni dla przypadków użycia, w których prędkość ma kluczowe znaczenie, jak granie online, streaming wideo, Voice over IP (VoIP) czy komunikacja między urządzeniami podłączonymi do sieci Internetu rzeczy (IoT), np. czujnikami wysyłającymi regularnie pewne dane
MQTT broker na ESP32
Biblioteka sMQTTBroker: https://github.com/terrorsl/sMQTTBroker
#include"sMQTTBroker.h"
sMQTTBroker broker;
void setup()
{
Serial.begin(115200);
const char* ssid = "matineo24";
const char* password = "bge9wfl3gwts8egu";
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { // Wait for the Wi-Fi to connect
delay(1000);
}
Serial.println("Connection established!");
Serial.print("IP address:\t");
Serial.println(WiFi.localIP()); //192.168.0.40
const unsigned short mqttPort=1883;
broker.init(mqttPort);
// all done
}
void loop()
{
broker.update();
}
ESP8266 broker
#include <ESP8266WiFi.h>
#include <espMQTTBroker.h>
const char* ssid = "Twoja_Siec_WiFi";
const char* password = "Twoje_Haslo_WiFi";
class MyMQTTBroker : public espMQTTBroker {
public:
void onConnect(IPAddress addr, uint16_t client_count) {
Serial.printf("Nowe połączenie MQTT z %s, Klientów: %d\n", addr.toString().c_str(), client_count);
}
void onDisconnect(IPAddress addr, String client_id, uint16_t client_count) {
Serial.printf("Rozłączono %s (ID: %s), Klientów: %d\n", addr.toString().c_str(), client_id.c_str(), client_count);
}
void onData(String topic, const char *data, uint32_t length) {
Serial.printf("Odebrano dane - Temat: %s, Wiadomość: %.*s\n", topic.c_str(), length, data);
}
};
MyMQTTBroker myBroker;
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Łączenie z WiFi...");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nPołączono z WiFi!");
Serial.print("Adres IP brokera MQTT: ");
Serial.println(WiFi.localIP());
myBroker.init(); // Start brokera MQTT
}
void loop() {
// Broker działa w tle, nic więcej nie trzeba w loop()
}
MQTT Explorer program
Link: https://mqtt-explorer.com/
Klient wysyłający dane, które inni mogą zasubskrybować
Biblioteka PubSubClient
#include <WiFi.h>
#include <PubSubClient.h>
const char* ssid = "matineo24";
const char* password = "bge9wfl3gwts8egu";
// Ustawienia brokera MQTT
const char* mqtt_server = "192.168.0.40"; // IP brokera MQTT (np. komputera z Pythonem)
const int mqtt_port = 1883;
const char* mqtt_topic = "x/counter";
WiFiClient espClient;
PubSubClient client(espClient);
int counter = 0; // Licznik wysyłanych wartości
// Funkcja łącząca z WiFi
void setup_wifi() {
delay(10);
Serial.println("Łączenie z WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nPołączono z WiFi!");
}
// Funkcja łącząca z brokerem MQTT
void reconnect() {
while (!client.connected()) {
Serial.print("Łączenie z MQTT...");
if (client.connect("ESP32_Client")) {
Serial.println(" Połączono!");
} else {
Serial.print(" Błąd: ");
Serial.print(client.state());
Serial.println(" Próba ponownego połączenia za 5 sekund...");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
// Wysyłanie liczby przez MQTT
counter++;
String message = String(counter);
client.publish(mqtt_topic, message.c_str());
Serial.print("Wysłano: ");
Serial.println(message);
delay(5000); // Czekaj 5 sekund
}
Klient subskrybujący dane
#include <WiFi.h>
#include <PubSubClient.h>
const char* ssid = "matineo24";
const char* password = "bge9wfl3gwts8egu";
// Ustawienia brokera MQTT
const char* mqtt_server = "192.168.0.40"; // IP brokera MQTT (np. komputera z Pythonem)
const int mqtt_port = 1883;
const char* mqtt_topic = "esp32/dane";
WiFiClient espClient;
PubSubClient client(espClient);
// Funkcja obsługi przychodzących wiadomości MQTT
void callback(char* topic, byte* message, unsigned int length) {
Serial.print("Otrzymano wiadomość na temat: ");
Serial.println(topic);
Serial.print("Wiadomość: ");
String receivedMessage = "";
for (int i = 0; i < length; i++) {
Serial.print((char)message[i]);
receivedMessage += (char)message[i];
}
Serial.println();
// Możesz dodać własne działania na podstawie odebranej wiadomości
if (receivedMessage == "ON") {
Serial.println("Włączono funkcję!");
} else if (receivedMessage == "OFF") {
Serial.println("Wyłączono funkcję!");
}
}
// Funkcja łącząca ESP32 z WiFi
void setup_wifi() {
delay(10);
Serial.println("Łączenie z WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nPołączono z WiFi!");
}
// Funkcja łącząca z brokerem MQTT
void reconnect() {
while (!client.connected()) {
Serial.print("Łączenie z MQTT...");
if (client.connect("ESP32_Subscriber")) {
Serial.println(" Połączono!");
client.subscribe(mqtt_topic);
} else {
Serial.print(" Błąd: ");
Serial.print(client.state());
Serial.println(" Próba ponownego połączenia za 5 sekund...");
delay(5000);
}
}
}
void setup() {
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
}
Wysyłanie danych przez MQTT w python
# pip install paho-mqtt
import paho.mqtt.client as mqtt
import time
import random
# Ustawienia brokera MQTT (podmień na IP swojego ESP32)
BROKER_IP = "192.168.0.40"
PORT = 1883
TOPIC = "esp32/dane"
# Tworzenie klienta MQTT
client = mqtt.Client()
# Łączenie z brokerem ESP32
client.connect(BROKER_IP, PORT, 60)
# Pętla wysyłająca losowe liczby co 3 sekundy
try:
while True:
random_number = random.randint(1, 100) # Generowanie liczby od 1 do 100
print(f"Wysyłam: {random_number}")
client.publish(TOPIC, str(random_number))
time.sleep(3) # Czekaj 3 sekundy przed kolejnym wysłaniem
except KeyboardInterrupt:
print("Zatrzymano wysyłanie.")
client.disconnect()
Odbieranie danych w python
import paho.mqtt.client as mqtt
# Ustawienia brokera MQTT
BROKER = "mqtt.eclipseprojects.io"
PORT = 1883
TOPIC = "test/topic"
# Funkcja callback wywoływana po otrzymaniu wiadomości
def on_message(client, userdata, message):
print(f"Otrzymano wiadomość: {message.payload.decode()} na temat: {message.topic}")
# Tworzenie klienta MQTT
client = mqtt.Client()
# Konfiguracja funkcji obsługi wiadomości
client.on_message = on_message
# Połączenie z brokerem
client.connect(BROKER, PORT, 60)
# Subskrybowanie tematu
client.subscribe(TOPIC)
# Start pętli nasłuchującej
client.loop_forever()