V současné době je protokol IP (Internet Protokol) nejrozšířenějším standardem pro komunikaci mezi počítači a zařízeními. Protokol je protokolem vyšší vrstvy na úrovni paketů, datagramů a spojení. Pro realizaci vlastního přenosu rámců po lokálních sítích se používá řada technologií, asi nejrozšířenější je technologie ETHERNET, která ve své základní podobě rámců ale neřeší přenos rámců mezi více sítěmi.

Obě technologie se tedy velmi dobře doplňují. Protokol IP existuje ve dvou verzích IPv4, který používá pro identifikaci rozhraní každého počítače ve světové síti 32-bitovou adresu. Postupně se pak přechází na novou verzi protokolu IPv6, který používá 128-bitové adresy s lépe propracovanými pravidly pro přiřazování a komunikaci.

Pro práci na semestrální úloze se předpokládá použití jednodušší verze IPv4. Nad základní síťovou vrstvou je definované množství dalších protokolů specializovaných pro rozdílné potřeby komunikace různých aplikací a druhů přenosu. Asi nejznámější je protokol TCP, který slouží pro zajištění zabezpečeného spojení s kompletním mechanizmem potvrzování přijetí dat. Proud dat je v případě ztráty paketu pozastavený a je zajištěné opětovné poslání nedoručených dat. protokol se používá například pro nejrozšířenější transportní aplikační protokoly a služby HTTP, HTTPS a SSH. Protokol TCP však není vhodný pro paralelní doručování zpráv se všeobecnou cílovou adresou všem účastníkům v rámci lokální sítě (Broadcast).

Aby bylo možné jednoduše vytvářet seznam všech připojených jednotek, bude se v rámci semstrální aplikace používat nezabezpečený, nespojovaný, datagramový protokol UDP. Tato volba umožňuje vysílat informaci o stavu jednotky do lokální sítě bez definování adresy určení. Takovéto zprávy pak mohou přijímat všechny jednotky na lokální síti.

Příklad jednoduchého programu v roli serveru a druhého v klienta lze nalézt například v návodu Beej's Guide to Network Programming.

Podrobnější how-to pro práci se sockety naleznete na stránkách bývalého předmětu X35POS v cvičení 4.

Hlavičkové soubory pro programy v jazyce C, které zpřístupňují soketové služby na systémech splňujících normu POSIX

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

Program, který přistupuje k těmto službám, musí nejdříve založit síťový socket

   int sockfd;

   if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

Volba AF_INET specifikuje adresní rodinu IPv4, SOCK_DGRAM pak volí nespojovanou službu UDP. Více o volání socket v Beej's Guide nebo v dokumentaci GNU C knihovny použité na systému GNU/Linux.

Volba lokálního portu, na kterém poté aplikace naslouchá a který je použitý spolu s IP adresou odchozího rozhraní počítače/jednotky se volí voláním bind (GNU).

Příklad jednoduchého zavázání IPv4 socketu na všechna lokální rozhraní. Port MY_PORT je 16-ti bitové číslo v rozsahu 0 až 65535. Síťové adresy jsou ukládané v paměťových strukturách již v síťovém pořadí bajtů, proto je potřeba převést interní (h = host) pořadí na síťové (n = network) pořadí bajtů. Porty v rozsahu 1 až 1000 jsou pak rezervované pro privilegované služby, mohou je používat jen programy s právy administrátora nebo přímého přístupu k síti.

  struct sockaddr_in bindaddr;

  memset(&bindaddr, 0, sizeof(bindaddr));
  bindaddr.sin_family = AF_INET;
  bindaddr.sin_port = htons(MY_PORT);
  bindaddr.sin_addr.s_addr = INADDR_ANY;

  if (bind(sockfd, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) == -1) {
    perror("bind");
    exit(1);
  }

Systém však po ukončení služby na určitém portu ještě po určitou dobu znovuvyužití portu rezervuje/blokuje, aby zpožděné, nezpracované příchozí pakety nekolidovaly s nově spuštěnou službou/programem. Proto je vhodné před voláním bind() odmítnout tuto blokaci pro službu, která musí běžet na pevném čísle portu.

  int yes=1;

  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                sizeof(yes)) == -1) {
    perror("setsockopt (SO_REUSEADDR)");
    exit(1);
  }

Protože by mohlo dojít k rozesílání datagramům všem jednotkám na lokální síti omylem, musí být tato volba povolena

    int broadcast = 1;

    if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &broadcast,
        sizeof broadcast) == -1) {
        perror("setsockopt (SO_BROADCAST)");
        exit(1);
    }

Dále je již možné k zasílání zpráv využít volání sendto a recvfrom.

IPv4 adresu pro hromadné rozeslání zprávy na všechny uzly v lokální síti je možné nastavit

  struct sockaddr_in braddr;

  memset(&braddr, 0, sizeof(braddr));
  braddr.sin_family = AF_INET;
  braddr.sin_port = htons(HELLO_SERVICE_PORT);
  braddr.sin_addr.s_addr = INADDR_BROADCAST;

courses/b35apo/documentation/networking.txt · Last modified: 2024/02/02 18:41 (external edit)