|
|
|
|
|
Protokol UDP 2.část
Dnes
dokončíme téma UDP. Neuvedeme si žádnou novou funkci. Pouze se
podíváme, že i na datagramový soket je možné zavolat funkci connect.
Článek je opět věnován operačnímu systému Linux i operačnímu systému MS
Windows. Na konci článku jsou ke stažení 2 příklady.
|
|
V minulém článku jsme si pověděli základní
informace o UDP a srovnali UDP s TCP, který jsme již znali z dřívějších článků. Několikrát jsem upozornil,
že při použití protokolu UDP nenavazujeme spojení. Nejedná se o spojovou službu. Přesto na datagramový soket lze
zavolat funkci connect. Nenavážeme s ní spojení. Její význam je trochu jiný.
V minulém díle jsme používali pro příjem a odeslání dat funkce
sendto a recvfrom.
Tyto funkce nám umožnili jedním soketem odesílat a přijímat data
kamkoliv a odkudkoliv (nebyli jsme vázání jednou adresou). Takové
požadavky na jeden soket ale většinou nemáme. Většinou vytváříme
soket, pomocí kterého chceme odesílat data na jedno místo (resp. je z
jednoho místa přijímat). V každém případě je časté, že funkce sendto
a recvfrom používáme několikrát za
sebou se stejnými parametry udávajícími adresu. Bylo by asi nepohodlné
ji
pořád psát (nebo dokonce strukturu několikrát plnit stejnými daty). Bylo
by ideální, kdyby jsme mohli nějak operačnímu systému říci, že tímto
datagramovým soketem budeme komunikovat jen se zadanou IP adresou a UDP
portem. Ať si ji zapamatuje a nechce ji po nás při každém odesíláni,
resp. přijímání dat. Až budeme chtít komunikovat s jinou IP adresou a
UDP portem, dáme operačnímu systému vědět. Jak vás asi napadlo, právě k
těmto účelům u datagramových soketů slouží funkce connect. Touto funkcí nenavážeme spojení, tak jak jsme
to dělali u protokolu TCP. Funkcí connect zavolanou na datagramový soket pouze oznámíme operačnímu systému, že tento soket
nějakou dobu bude komunikovat se zadanou IP adresou a UDP portem (daný instancí struktury sockaddr_in).
Tím pádem
je zbytečné, aby jsme při odesílání (resp. při přijímání) dat tímto
soketem museli neustále zadávat kam (resp. odkud) data posíláme
(přijímáme). Proto
nemusíme používat sendto a recvfrom, ale můžeme použít send
a recv. Funkce sendto se od send liší pouze v tom, že
udáváme také adresu a port příjemce. Budeme-li chtít změnit adresu a port druhé strany, jednoduše znovu zavoláme connect
s novými hodnotami.
Díky toho můžeme používat v podstatě stejné funkce pro naprosto
odlišné protokoly jakými jsou UDP a TCP. Podívejme se na použití connect
a následné použití send a recv
u UDP protokolu. Uvedeme si UDP klienta v Linuxu Na základě tohoto
zdrojového textu je snadné vytvořit UDP klienta v MS Windows®. Navíc
jsou na závěr článku oba
příklady ke stažení.
UDP klient v Linuxu
#include <iostream>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <netdb.h>
#define BUFSIZE 1000
using namespace std;
int main(int argc, char *argv[])
{
hostent *host; // Vzdálený počítač
sockaddr_in serverSock; // Vzdálený "konec potrubí"
int mySocket; // Soket
int port; // číslo portu
char buf[BUFSIZE]; // Přijímací buffer
int size; // Počet přijatých a odeslaných bytů
socklen_t addrlen; // Velikost adresy
if (argc != 3)
{
cerr << "Syntaxe:\n\t" << argv[0]
<< " " << "adresa port" << endl;
return -1;
}
port = atoi(argv[2]);
// Zjistíme info o vzdáleném počítači
if ((host = gethostbyname(argv[1])) == NULL)
{
cerr << "Špatná adresa" << endl;
return -1;
}
// Vytvoříme soket
if ((mySocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
cerr << "Nelze vytvořit soket" << endl;
return -1;
}
// Zaplníme strukturu sockaddr_in
// 1) Rodina protokolů
serverSock.sin_family = AF_INET;
// 2) číslo portu, ke kterému se připojíme
serverSock.sin_port = htons(port);
// 3) Nastavení IP adresy, ke které se připojíme
memcpy(&(serverSock.sin_addr), host->h_addr, host->h_length);
if (connect(mySocket, (sockaddr*)&serverSock, sizeof(serverSock)) == -1)
{
cerr << "Problém s přiřazením cílové adresy soketu" << endl;
return -1;
}
for (register int i = 0; i < 5; i++)
{
char temp[30];
// Odeslání dat
sprintf(temp,Datagram číslo "%d\n",i);
if ((size = send(mySocket, temp, strlen(temp), 0)) == -1)
{
cerr << "Problém s odesláním dat" << endl;
return -1;
}
cout << "Odesláno " << size << endl;
// Příjem dat
if ((size = recv(mySocket, buf, BUFSIZE, 0)) == -1)
{
cerr << "Problém s přijetím dat" << endl;
return -1;
}
cout << "Přijato " << size << endl;
buf[size] = '\0';
cout << buf << endl;
}
close(mySocket);
return 0;
}
|
|
Příklady ke stažení
Tyto příklady lze v komunikaci libovolně kombinovat s příklady z
minulého dílu. Můžete si vyzkoušet, že UDP klientem se na TCP server
nepřipojíte a naopak. Také si všimněte,
že příklady z tohoto článku se velice podobají příkladům z článků o TCP
protokolu. Zkuste si také spustit na jednom počítači TCP server a UDP
server se stejným číslem portu.
Porty mají stejné číslo, ale stejné nejsou. V jednom případě se jedná o
UDP port, v druhém případě se jedná o TCP port. Takže to bez problému
půjde.
Při komunikaci pomocí soketů nemusí vše fungovat tak, jak by jsme si
představovali. Při práci se sokety mohou nastat chyby (nelze odeslat
data, nelze navázat spojení atd...). Bylo
by dobré tyto chyby umět identifikovat a umět pracovat s nimi. Způsob
identifikace chyb se v Unixových systémech a v MS Windows® liší. Proto
příště opět dočasně rozdělíme
seriál na články pro MS Windows® a pro Linux®. Bude to takové oddechové
téma (pro někoho možná zbytečné), ale měli by jsme se na něj podívat.
Tím budeme mít za sebou základy práce s TCP a UDP pomocí soketů v
blokovacím režimu. Pak se budeme moci vydat dále.
Hodnocení článku |
1 |
2 |
3 |
4 |
5 Aktuální známka: 2.59 (Počet známek: 3643)
|
|
|
|
|
|