Portál AbcLinuxu, 11. května 2025 10:15

Dotaz: sockety a c++

8.11.2010 15:10 pedraz
sockety a c++
Přečteno: 789×
Odpovědět | Admin
Zdravím potřeboval bych poradit s aplikací klient-server: Klient každou minutu posílá data serveru, který je pak dál zpracovává. Jde mi o to jak udělat, aby se klient připojil jen jednou a pak už jen periodicky odesílal data a aby se na server mohlo připojit více klientů. Díky.
Nástroje: Začni sledovat (2) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

8.11.2010 15:24 Michal Kubeček | skóre: 72 | Luštěnice
Rozbalit Rozbalit vše Re: sockety a c++
Odpovědět | | Sbalit | Link | Blokovat | Admin
To je spíš na článek než na odpověď do poradny…
8.11.2010 15:36 pedraz
Rozbalit Rozbalit vše Re: sockety a c++
Tak já to trochu upřesním: Jaký režim socketů použít (blokovací x neblokovací), udělat server jedno nebo více vláknový. Tak aby impementace byla co nejednoduší a fungovalo to:-).
8.11.2010 16:06 miso | skóre: 36 | blog: iSCSI_initiator_howto | Praha
Rozbalit Rozbalit vše Re: sockety a c++
Idealne blokovaci a viacvlaknovy. Z dotazu ale nie je jasne, comu presne nerozumies - potrebujes poradit s dokumentaciou?
Project Satan infects Calculon with Werecar virus
8.11.2010 16:32 pedraz
Rozbalit Rozbalit vše Re: sockety a c++
Projíždím si příklady se z http://www.builder.cz/serial147.html a http://www.root.cz/serialy/sokety-a-cc/ a není mi jasné jak udělat, aby ten klient posílal data v nějakém zadaném intevalu tomu serveru, připojil se pouze na začátku (connect) a pak už jen pomocí send a recv komunikoval se serverem. Např. aby mu každou minutu poslal nějaké číslo a server mu potvrdil příjem a vytiskl ho do konzole.
8.11.2010 18:54 rastos | skóre: 63 | blog: rastos
Rozbalit Rozbalit vše Re: sockety a c++
není mi jasné jak udělat, aby ten klient posílal data v nějakém zadaném intevalu tomu serveru
Pýtaš sa, ako zariadiť, aby program nejakú dobu nerobil nič?

sleep
, připojil se pouze na začátku (connect) a pak už jen pomocí send a recv komunikoval se serverem.
Vyrobíš socket, dostaneš handle, a ten budeš používať po celú dobu behu programu.

Ak ti to pripadá, ako blbá odpoveď, tak to bude tým, ako bola položená otázka. Skús si svoju otázku prečítať so odstupom a z pohľadu niekoho, kto nevie čo riešiš a nevie ani či zápasíš s kompiláciou, alebo hľadáš nejakú knižnicu, alebo nevieš aké funkcie použiť, ....
8.11.2010 19:56 pedraz
Rozbalit Rozbalit vše Re: sockety a c++
Omlouvám se za blbě položený dotaz. Já jsem se v tom kompletně ztratil. Přidávám zdrojáky klienta a servera. V tomto případě se klient připojí, odešle pozdrav serveru, přijme pozdrav od serveru a odpojí se. Server takto obslouží tři klienty ukončí se. A mně jde o to jak udělat aby se ten klient připojil, zůstal připojený a každou minutu poslal serveru ten pozdrav a přijal odpověd. Snad je to už jasné.:-) Díky moc.

klient:
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>



#define BUFSIZE 1000

using namespace std;

int main(int argc, char *argv[])
{
    std::string text("Ahoj\n"); // Odesilany a prijimany text
    hostent *host;              // Vzdaleny pocitac
    sockaddr_in serverSock;     // Vzdaleny "konec potrubi"
    int mySocket;               // Soket
    int port;                   // Cislo portu
    char buf[BUFSIZE];          // Prijimaci buffer
    int size;                   // Pocet prijatych a odeslanych bytu
    if (argc != 3)
    {
        cerr << "Syntaxe:\n\t" << argv[0]
             << " " << "adresa port" << endl;
        return -1;
    }
    port = atoi(argv[2]);
    // Zjistime info o vzdalenem pocitaci
    if ((host = gethostbyname(argv[1])) == NULL)
    {
        cerr << "Spatna adresa" << endl;
        return -1;
    }
    // Vytvorime soket
    if ((mySocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
    {
        cerr << "Nelze vytvorit soket" << endl;
        return -1;
    }
    // Zaplnime strukturu sockaddr_in
    // 1) Rodina protokolu
    serverSock.sin_family = AF_INET;
    // 2) Cislo portu, ke kteremu se pripojime
    serverSock.sin_port = htons(port);
    // 3) Nastaveni IP adresy, ke ktere se pripojime
    memcpy(&(serverSock.sin_addr), host->h_addr, host->h_length);
    // Pripojeni soketu
    if (connect(mySocket, (sockaddr *)&serverSock, sizeof(serverSock)) == -1)
    {
        cerr << "Nelze navazat spojeni" << endl;
        return -1;
    }
    // Odeslani dat
    if ((size = send(mySocket, text.c_str(), text.size() + 1, 0)) == -1)
    {
        cerr << "Problem s odeslenim dat" << endl;
        return -1;
    }
    cout << "Odeslano " << size << endl;
    // Prijem dat
    text = "";
    while (((size = recv(mySocket, buf, BUFSIZE - 1, 0)) != -1) && (size != 0))
    {
        cout << "Prijato " << size << endl;
        text += buf;
    }
    // Uzavru spojení
    close(mySocket);
    cout << endl << text << endl;
    return 0;
}
server:
#include <iostream>
#include <iterator>
#include <fstream>
#include <string>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>


#define BUFSIZE 1000

using namespace std;

int main(int argc, char *argv[])
{
   std::string text;             // Prijimany text
   sockaddr_in sockName;         // "Jmeno" portu
   sockaddr_in clientInfo;       // Klient, ktery se pripojil 
   int mainSocket;               // Soket
   int port;                     // Cislo portu
   char buf[BUFSIZE];            // Prijimaci buffer
   int size;                     // Pocet prijatych a odeslanych bytu
   socklen_t addrlen;            // Velikost adresy vzdaleneho pocitace
   int count = 0;                // Pocet pripojeni

   if (argc != 2)
   {
     cerr << "Syntaxe:\n\t" << argv[0]
	  << " " << "port" << endl;
     return -1;
   }
   port = atoi(argv[1]);
   // Vytvorime soket - viz minuly dil
   if ((mainSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
   {
     cerr << "Nelze vytvorit soket" << endl;
     return -1;
   }
   // Zaplnime strukturu sockaddr_in
   // 1) Rodina protokolu
   sockName.sin_family = AF_INET;
   // 2) Cislo portu, na kterem cekame
   sockName.sin_port = htons(port);
   // 3) Nastaveni IP adresy lokalni sitove karty, pres kterou je mozno se
   //    pripojit. Nastavime moznost pripojit se odkudkoliv. 
   sockName.sin_addr.s_addr = INADDR_ANY;
   // priradime soketu jmeno
   if (bind(mainSocket, (sockaddr *)&sockName, sizeof(sockName)) == -1)
   {
     cerr << "Problem s pojmenovanim soketu." << endl;
     return -1;
   }
   // Vytvorime frontu pozadavku na spojeni. 
   // Vytvorime frontu maximalni velikosti 10 pozadavku.
   if (listen(mainSocket, 10) == -1)
   {
     cerr << "Problem s vytvorenim fronty" << endl;
     return -1;
   }
   do
   {
     // Poznacim si velikost struktury clientInfo.
     // Predam to funkci accept. 
     addrlen = sizeof(clientInfo);
     // Vyberu z fronty pozadavek na spojeni.
     // "client" je novy soket spojujici klienta se serverem.
     int client = accept(mainSocket, (sockaddr*)&clientInfo, &addrlen);
     int totalSize = 0;
     if (client == -1)
     {
       cerr << "Problem s prijetim spojeni" << endl;
       return -1;
     }
     // Zjistim IP klienta.
     cout << "Nekdo se pripojil z adresy: " 
	  << inet_ntoa((in_addr)clientInfo.sin_addr) << endl;
     // Prijmu data. Ke komunikaci s klientem pouzivam soket "client"
     text = "";
     // Prijmeme maximalne 6 bytovy pozdrav. 
    while (totalSize != 6)
    //{
       if ((size = recv(client, buf, BUFSIZE - 1, 0)) == -1)
       {
	 cerr << "Problem s prijetim dat." << endl;
	 return -1;
       }
       cout << "Prijato: " << size << endl;
       totalSize += size;
       text += buf;
    }
     cout << text << endl;
     // Odeslu pozdrav
     if ((size = send(client, "Nazdar\n", 8, 0)) == -1)
     {
       cerr << "Problem s odeslenim dat" << endl;
       return -1;
     }
     cout << "Odeslano: " << size << endl;
     // Uzavru spojeni s klientem
    close(client);
   }
   while (++count != 3);
   cout << "Koncim" << endl;
   close(mainSocket);
   return 0;
}
8.11.2010 20:34 rastos | skóre: 63 | blog: rastos
Rozbalit Rozbalit vše Re: sockety a c++
Na strane klienta je to jednoduché
for (;;)
{
 // Odeslani dat
    if ((size = send(mySocket, text.c_str(), text.size() + 1, 0)) == -1)
    {
        cerr << "Problem s odeslenim dat" << endl;
        return -1;
    }
    cout << "Odeslano " << size << endl;
    // Prijem dat
    text = "";
    while (((size = recv(mySocket, buf, BUFSIZE - 1, 0)) != -1) && (size != 0))
    {
        cout << "Prijato " << size << endl;
        text += buf;
    }
    sleep(5);
}
Na strane servera tiež môžeš jednoducho urobiť loop, ktorý ide do nekonečna a postupne bude obsluhovať klientov. Ak by mal obsluhovať viacero klientov naraz, je to trocha komplikovanejšie. Ak si dobre spomínam, tak server čaká v accept(). Keď sa klient pripojí, tak accept() prejde a klient sa môže baviť so serverom, ale zároveň môžeš znova vykonávať accept(). Napr. v inom threade.
9.11.2010 00:18 asi si ten profil uz vazne zalozim
Rozbalit Rozbalit vše Re: sockety a c++

Pokusim se ten server vyjadrit kusem pseudokodu, berte to prosim s rezervou.V realu se krome chybovych stavu musi take zpracovat zavrena spojeni (preskladat sadu descriptoru apod.). Thready bych radil rozhodne nepouzivat.

Btw nechcete v tomto pripade pouzit radsi UDP? Bylo by to podstatne jednodussi s totoznym vysledkem (pouze s rizikem sem tam ztraceneho UDP datagramu)

PS: U TCP bych v klientovi doporucoval nespolehat se na to, ze se vsechna data podari odeslat naraz na jeden send.

cokoli set_nonblock(int fd)
{ // man fcntl
  int flags = fcntl(fd, F_GETFL, 0);
  fcntl(fd, F_SETFL, O_NONBLOCK | flags);
  // v realu vsude kontrolovat navratove hodnoty
  // throw, return atd.
}
...
server = socket, set_nonblock, bind, listen
...
// man poll
// google poll example
...
vlozit_do_poll_sady(server); // na prvni misto
...
while (furt)
{
  vynuluj a nastav (r)eventy v cele sade;
  poll(...);
  prvek = prvni_v_sade;
  if ( POLLIN == (POLLIN & prvek->revents) )
  { // mame prichozi spojeni
    novy_socket = accept(prvek->fd, ...);
    ...
    set_nonblock(novy_socket);
    vlozit_do_poll_sady(novy_socket);
  }
  for (prvek = dalsi_v_sade; az_do_konce)
    if ( POLLIN == (POLLIN & prvek->revents) )
      proved_read(prvek->fd);
}
9.11.2010 14:40 pedraz
Rozbalit Rozbalit vše Re: sockety a c++
Díky za ten pseudokód, pomohlo mi to:-). Ještě jsem se chtěl zeptat jak by šlo zajistit, aby klient a server komunikovali šifrovaně (např. přes SSH tunel). Díky
9.11.2010 14:49 pedraz
Rozbalit Rozbalit vše Re: sockety a c++
Teď asi míchám jabka s hruškama:-[
9.11.2010 15:32 Michal Kubeček | skóre: 72 | Luštěnice
Rozbalit Rozbalit vše Re: sockety a c++
Pokud to chcete řešit přímo v aplikaci, použijte OpenSSL. Pokud mimo ni, tak třeba stunnel.
9.11.2010 18:02 asi si ten profil uz vazne zalozim
Rozbalit Rozbalit vše Re: sockety a c++

Implementace pomoci OpenSSL neni uplne trivialni zalezitost, pokud to ma fungovat spravne (osetrovat vsechny stavy, provest SSL handshake, renegociace apod.).

Uplne nejjednodussi reseni by bylo pustit server aplikaci na serveru na localhostu, z klienta (stroje) udelat SSH tunel na server a klientskou aplikaci se pripojovat na tento tunel. Napr. (opet s rezervou)

server:

# server_app --addr 127.0.0.1 --port 9999

klient:

# ssh -N -L localhost:1234:localhost:9999 server
# client_app --addr 127.0.0.1 --port 1234

10.11.2010 13:20 pedraz
Rozbalit Rozbalit vše Re: sockety a c++
Díky všem za pomoc. Ještě bych se chtěl zeptat, jestli nějak jde přímo v c++ přistupovat k informacím jako je teplota cpu a hdd, otáčky větráčků, spuštěné procesy atd. Zatím je čtu tak že přes fci systém() ukládám do textového souboru a tak pak zpracovávám. Díky
10.11.2010 13:43 Messa | skóre: 39 | blog: Messa
Rozbalit Rozbalit vše Re: sockety a c++
Přes fci system() spouštíš jen další program, který je nejspíš opět v C a něco dělá. Takže to něco můžeš dělat rovnou ty :) Typicky se na Linuxu jedná o čtení odněkud z /proc nebo /sys, protože přímo na hardware si z userspace sáhnout pochopitelně nemůžeš.
10.11.2010 14:37 pedraz
Rozbalit Rozbalit vše Re: sockety a c++
V té fci system() spouštím bashovské příkazy a přesměrovávám je do toho texťáku. Právě té práci s tím texťákem bych se chtěl vyhnout tak, že bych ty údaje doloval přímo v c a ukládal je rovnou do proměných.
10.11.2010 14:48 Denwerko | skóre: 2
Rozbalit Rozbalit vše Re: sockety a c++
hmm... a nebolo by lepšie vynechať ukladanie do textoveho suboru a namiesto toho pomocou fork, pipe, execve ( napr ) dostať vystup tych prikazov ?

no offence, čisto teoreticky...

Založit nové vláknoNahoru

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.