» »

C: connect() funkcija, kako nastaviti timeout

C: connect() funkcija, kako nastaviti timeout

fefko-the-bulldog ::

Pišem preprost port scanner v Cju pod Linuxom, in sem naletel ne težavo: ko program pride do vrstice

connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr))

obtiči. Če je skenirani računalnik localhost, pa ne. Torej: se da nekako nastaviti, po kolikem času bo program opustil povezovanje na določen port skeniranega računalnika? V bistvu sem v tem programiranju s socketi še precej začetnik, tako da bi prosil za nasvete pri tej stvari - če se da stvar kako drugače rešiti kot s timeouti.

Hvala!

Gundolf ::

Stvari ki ti rade blokirajo program iz tega ali onega razloga je dobro imeti v svojem threadu, ki ga lahko v skrajnem primeru killas. Drugace se pa ne spoznam na connectanje v linuxu tako da ti ne znam pomagat :'( .

fefko-the-bulldog ::

Ja, to je ena rešitev, samo rad bi rešil vse skupaj bolj enostavno, da bi pač povezavo, za katero vidim, da je neuspešna, ubil. In bi tudi za vnaprej vedel, kako se to naredi ;) ! Zanima me tudi, zakaj se pri povezovanju na nek zunanji IP ustavi, pri povezovanju na lokalnega pa neuspešen poizkus lepo preskoči in nadaljuje...

CCfly ::

connect mora vrniti -1 v nastaviti errno, če je omrežje nedosegljivo. Da bi pa to poizvedovanje časovno omejil, je pa res še najbolj primerna nit ali pa drug proces. Morda ima kdo boljšo idejo ?
"My goodness, we forgot generics!" -- Danny Kalev

BigWhale ::

setsockopt (sock_fd, SOL_SOCKET, SO_RCVTIMEO, timeout, sizeof *timeout);

man socket
man 7 socket
man setsockopt
man bind
man connect


;)

PS: Predstavljajte si kako bi zgledal program, ki odpre 1024 portov enega za drugim in za vsak port naredi svoj thread...;)

Zgodovina sprememb…

  • spremenil: BigWhale ()

BigWhale ::

Sicer pa fefko, najbrz se ti zaustavi iz dolocenega razloga... daj celo kodo zalimaj..

Se tisto kako klices bind() in gethostbyname()

fefko-the-bulldog ::

Evo, koda:

#include (sys/types.h)
#include (sys/socket.h)
#include (netinet/in.h)
#include (arpa/inet.h)
#include (netdb.h)
#include (stdio.h)
#include (unistd.h)

int main (int argc, char *argv[]) {

if(argc(3){
printf("Uporaba: %s (IP) (Zacetna vrata) (Koncna vrata)\n\nPrimer: %s 127.0.0.1 1 65530\n", argv[0], argv[0]);
exit(0);
}

int sock;
int z = atoi(argv[2]);
int k = atoi(argv[3]);
struct sockaddr_in servAddr;
struct hostent *hp, *gethostbyname();

if ( (sock = socket(AF_INET, SOCK_STREAM, 0)) ( 0) {
printf("Ne morem ustvariti socketa.\n");
exit(1);
}
printf("Socket ustvarjen...\n");

bzero( (char *) &servAddr, sizeof(servAddr));
servAddr.sin_family = AF_INET;
hp = gethostbyname(argv[1]);
bcopy(hp-)h_addr, &servAddr.sin_addr, hp-)h_length);

printf("Odprti porti:\n\n");

for(z; z (= k;z++){
servAddr.sin_port = htons(z);
if (connect(sock, (struct sockaddr *) &servAddr, sizeof(servAddr)) )= 0){
printf("IP: %s Vrata: %i\n", argv[1], z);
close(sock);
if ( (sock = socket(AF_INET, SOCK_STREAM, 0)) ( 0) {
printf("\nNe morem ustvariti socketa (ponovno).\n");
exit(1);
}
}
}

return 0;

}


Oglate oklepaje sem zamenjal z navadnimi.

Upam, da pomaga...

fefko-the-bulldog ::

Da ne pozabim: hvala BigWhale ;) !

CCfly ::

BigWhale is the whale :)
"My goodness, we forgot generics!" -- Danny Kalev

64202 ::

Ce hoces se malo bol advanced: uporabi select() klic in nonblocking flag na socketih. Odpres in povezes lahko recimo 1000 socketov naenkrat (omejeno s strani kernela per process) in potem v loopu cakas na evente na celem "arrayu" socketov. Se tako bolj ali manj elegantno izognes threadom, zadeva pa deluje vzporedno.

fefko-the-bulldog ::

Ja, ta zadnja je zame res še malo preveč "advanced" :) ! Bi blo pa verjetno res precej pametno to naredit, odpraš jih 1000 potem jih pa čez pol minute pobiješ pa je :P ...

Hvala za odgovore!

fefko-the-bulldog ::

Opa, očitno tole z setsockopt ne bo prava rešitev :'( ... Da ponovim: program se poizkuša povezati na neki port, a ta je zaprt. Nato se funkcija connect() izvaja zelo dolgo... Funkcijo setsockopt pa se izgleda kliče, ko je povezava že vzpostavljena, in določi timeout na čisto nekaj drugega :'( ...

Potem pa najdem še tole:

http://www.manualy.sk/sock-faq/unix-soc...

3.5 How can I set the timeout for the connect() system call?

From Richard Stevens ( rstevens@noao.edu):

Normally you cannot change this. Solaris does let you do this, on a per-kernel basis with the ndd tcp_ip_abort_cinterval parameter.
.
.
.

Tako da nič ne bo iz tega, bom moral zgleda res uporabiti threade :'( ...

64202 ::

select() se je 120% lazje nauciti, kot pa (pravilno!) s threadi delati, verjemi (n let tegob v c-ju:). Pa se direktno resi tvoj problem timeouta in deluje povsod[tm], tudi na winsih.

Zgodovina sprememb…

  • spremenilo: 64202 ()

Gundolf ::

Poslusaj 64202. Ce imas na voljo neblokirajoco funkcijo jo uporabi. S threadi zafrkavat se je sigurno vec dela in vec prostora za napako. Je pa res, da je dobro znati osnove threadov, ker znajo kdaj se prav priti.

BigWhale ::

KHM!

Tvoj program dela tocno tako kot si mu ti rekel naj dela... ;) Tudi setsockopt() dela v linuxu tako kot treba... V cem je problem, ti klices connect(), ce poves programu naj skenira porte od 1-65535, se bo connect klical 65535 krat... :) Vsak connect nekaj casa traja.

Z bind() se ti ne povezes na port ampak samo dodelis lokalen IP naslov file descriptorju, ki predstavlja socket. Povezava se vzpostavi, ko klices connect()! Setsockopt() pa poklices preden klices connect... ;)

Poglej si tisti if v katerem klices connect(), daj se tole zraven

else { printf("Error: %d\n, errno); }

Bos dejansko videl do kaksnega errorja pride.

Ce ti connect() vrne ECONNREFUSED, kar pomeni, da je bil host dosegljiv ampak da port ni odprt, se to zgodi prakticno takoj. Tukaj nastavljati kakrsen koli timeout je brez veze.

Host unreachable error traja kako sekundo, dve... Zato napisi program tako, da ko prvic naleti na unreachable host, da neha sniffat za ostalimi porti... :)

Threadi so no go, to je najbolj butasta resitev... ;)

fefko-the-bulldog ::

Problem je bil čisto drugje :D ... Program sem preizkušal le na mojem računalniku... Ker imam na routerju nastavljeno, da se ne oglaša na pinge, je bil program počasen... Vrnil pa je napako 110 (ETIMEDOUT). Na to sploh nisem pomislil, sedaj sem ga preizkusil na na drugem računalniku, kjer je deloval normalno :) .

Kako bi pa na to nastavil timeout?

Vesoljc ::

jah nared svoj timer 8-)
Abnormal behavior of abnormal brain makes me normal...

fefko-the-bulldog ::

Vesoljc: a lahko malo obrazložiš? S Cjem sem šele dobro začel ;) ....

BigWhale ::

> Ker imam na routerju nastavljeno, da se ne oglaša na pinge, je bil
> program počasen...

Pingi, s tem nimajo glih veze... Ti se poizkusas povezat na nek dolocen port, kar je bustveno drugace kot pa ping....

Vprasanje kaj imas zaprto na routerju ;)

fefko-the-bulldog ::

Ja ja, vem za razliko med pingi in povezovanji na določen port :)) .... Samo prehitro sem sklepal :) ... Da ne bom kompliciral: kako nastaviti timeout na tiste povezovanja, ki vrnejo napako ETIMEDOUT - to mi sedaj ponavadi vrže ven po kakih 3 minutah?

64202 ::

Gundolf: in kaj sem jaz napisal? select() je dalec najbolj portable zadeva, da se resis setsockopt hekov in threadov.

64202 ::

koda za select()
(sem skoraj cisto z glave stresel, bi pa moralo delati, detajli so itak v man page-ih:)

int s = socket(...blabla);

// vklopis non-blocking
int nblk = 1;
if(0 != ioctl(s, FIONBIO, &nblk))
    // napaka

// connect zdaj takoj vrne
if(connect(s, ...) == 0)
  // takoj se je skonektal (localhost)
else if(errno == EINPROGRESS) {
    // pocakamo da se povezovanje konca, s select() crno magijo :)

    // "mnozice" socketov za lovljenje eventov, nastavimo samo nas socket s
    fd_set r, w, e; 
    FD_ZERO(&r); FD_ZERO(&w); FD_ZERO(&e);
    FD_SET(s, &r); FD_SET(s, &w); FD_SET(s, &e);

    timeval tv; // pocakamo recimo 3.5 sekunde
    tv.tv_sec = 3;
    tv.tv_usec = 500000;

    int sel = select(s+1, &r, &w, &e, &tv);
    if(sel == 0)
        // timeout!
    else if(sel > 0) {
        // zgodil se je read ali write ali error (exception?) event na socketu
        if(FD_ISSET(s, &e))
            // napaka pri connectu
        else
            // ok!
    } else
         // select je crknil iz razloga x (tudi to se zgodi, ampak zaenkrat pozabi:)
} else
   // napaka


Na podoben nacin lahko pohendlas n socketov naenkrat, samo da nasopas notri FD_SET za vsakega posebej. Potem moras za vsakega posebej v for zanki s FD_ISSET preveriti, ali se je tocno na njemu zgodil event.

Gundolf ::

Aja sori 64202, zdajle vidim kako se je slisal moj tekst. Moral bi napisati fefko, ti kar poslusaj 6402. :D

fefko-the-bulldog ::

64202: Hvala za kodo, vključil sem jo skoraj brez problemov, sedaj dela tako kot hočem :) !

Hvala vsem, rešeno ;) !


Vredno ogleda ...

TemaSporočilaOglediZadnje sporočilo
TemaSporočilaOglediZadnje sporočilo
»

[c] ne sprejme UDP paketa

Oddelek: Programiranje
7920 (508) slovencl
»

[C++] bind

Oddelek: Programiranje
61361 (1139) fiction
»

SMTP v c -ju

Oddelek: Programiranje
282055 (1196) BigWhale
»

Delo z omrezjem v linuxu

Oddelek: Programiranje
101215 (1061) CCfly
»

Casovni problem v C/C++

Oddelek: Programiranje
91185 (1086) sid_dabster

Več podobnih tem