Jump to content
Elohim

[Ajutor] [C] Non-blocking socket example ?

Recommended Posts

Am si eu nevoie de un exemplu de o initializare a unui socket non-blocking ( pentru recv() sau global ) impreuna cu un timeout. Nu am incercat nimic inca, sunt ceva exemple pe stackoverflow, unul mai in ceata decat celalalt.

De preferat C, daca nu, C++

Multumesc in avans.

Link to comment
Share on other sites

  • Active Members

Uite, sper sa iti fie de ajutor.

socket_inet_server.c

#include <stdio.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

/*

Author: MrGrj

Programming Language: C

Enjoy :)

*/

struct sockaddr_in sockserv;

struct sockaddr_in from;

int fromlen = sizeof (from),portno,pid=1;

char msg[30],* fromip,buf[30];

int ss,newsock[5],i=1;

pthread_t tid[5];

//.................thread-uri multiple...........

void conexiune(void *socket_desc)

{

int newsock = *(int*)socket_desc;

read(newsock,msg,30);

fromip=inet_ntoa(from.sin_addr);

printf("received folowing message - \" %s \" from ip=%s port=%d\n",msg,fromip,ntohs(from.sin_port));

sprintf(buf,"\nOK! Got it! %d\n",pthread_self());

write(newsock,buf,sizeof(buf));

}

//.................thread-uri multiple...........

int main()

{

if ((ss = socket(AF_INET, SOCK_STREAM, 0)) < 0)

{

perror("server: socket");

_exit(1);

}

sockserv.sin_family=AF_INET;

portno=60080;

sockserv.sin_port=htons(portno);

inet_aton("127.0.0.1", &sockserv.sin_addr);

if (bind(ss, (struct sockaddr *)&sockserv, sizeof(sockserv)) < 0)

{

perror("server: bind");

_exit(1);

}

listen(ss,2);

/*--------------------------varianta cu procese multiple

while(i<3)

{

newsock = accept(ss, (struct sockaddr *)&from, &fromlen);

printf("\n%d connected\n",i);

i++;

printf("\nbefore fork.... pid=%d ppid=%d\n",getpid(),getppid());

if(pid!=0)

pid=fork();

printf("\nafter fork.... pid=%d ppid=%d\n",getpid(),getppid());

if(pid==0)

{

read(newsock,msg,30);

fromip=inet_ntoa(from.sin_addr);

printf("received folowing message - \" %s \" from ip=%s port=%d\n",msg,fromip,ntohs(from.sin_port));

sprintf(buf,"\nOK pid=%d ppid=%d\n",getpid(),getppid());

write(newsock,buf,sizeof(buf));

sleep(10);

}

else

{

printf("\nclosing pid=%d ppid=%d\n",getpid(),getppid());

close(newsock);

}

}

//------------------varianta cu procese multiple */

//.................thread-uri multiple...........

while(i<3)

{

newsock = accept(ss, (struct sockaddr *)&from, &fromlen);

printf("\n%d connected\n",i);

pthread_create(&tid,NULL,conexiune,(void*)&newsock);

i++;

}

pthread_join(tid[1],NULL);

pthread_join(tid[2],NULL);

//.................thread-uri multiple...........

sleep(10);

close(newsock);

close(ss);

_exit(0);

}

Link to comment
Share on other sites

@aelius, fix acel articol l-am recitit de peste 30 de ori pana sa postez acest thread. Motivul era ca preferam sa nu folosesc select() . Cred ca inca un lucru care l-am omis sa specific, este ca ma intereseaza acest lucru dpdv al client-ului, nu al server-ului.

Exemplu foarte scurt:

EU.connect -> server

Server -> "hey"

Eu -> "sup mofo?"

Server ->

In cazul in care Server refuza sa imi mai dea vreun mesaj inapoi, dar nici nu imi inchide sesiunea, risc sa stau cu socket-ul pornit pana inchid programul, lucru care incerc sa il evit. Multe exemple implica select(), nu am nici cel mai mic motiv sa evit aceasta functie, dar abia am inceput cu C, si select mi se pare un pic peste mine.

Se pare ca trebuie sa mai citesc.

Multumesc pentru ajutor.

Daca mai doreste cineva sa isi exprime parerea cu un exemplu, nu neaparat de pe Google, este binevenit.

Link to comment
Share on other sites

Salut,

Invata si foloseste select + FD_CLR, FD_ISSET, FD_SET, FD_ZERO.

Ce face: iti permite sa verifici daca pe unul sau mai multi socketi ai date de intrare, date de iesire sau erori. Adica daca ai primit date (in cozile din kernel) pe acel socket, daca urmeaza sa fie trimise date pe acel socket sau daca a intervenit o eroare pe acel socket, de exemplu inchiderea conexiunii.

Ce e important la acest "select" e ca poti "astepta" pe un socket un anumit interval (sau poti sa nu astepti) sa se intample un astfel de eveniment (primire date de exemplu). Adica poti verifica daca pe socket ai date de intrare. Daca ai, le procesezi, daca nu ai, treci mai departe. Sau poti astepta 3000 ms sa primesti date. Dupa 3000 ms, daca ai primit date, le procesezi, daca nu, faci altceva.

Nu e foarte complicat si sunt tutoriale care explica in detaliu acest syscall.

PS: Daca vrei Windows, pe langa select, ai o serie completa de functii asincrone (cele cu Async) care au ca parametru o functie callback care e apelata exact cand e declansat un eveniment (ca primirea de date).

  • Upvote 1
Link to comment
Share on other sites

select este foarte util (mai ales pe partea de server) dupa ce ai invatat sa-l folosesti dar daca am inteles bine tu cauti un recv care sa faca timeout si in cazul asta select e overkill.

recv va returna -1 cu eroarea WSAEWOULDBLOCK atunci cand incerci sa citesti dintr-un socket non-blocking unde nu este nimic de citit asa ca e simplu sa pui recv intr-un loop verificand diferenta de timp.

Ti-am facut un exemplu rapid pentru win:


#include <winsock2.h>
#include <stdio.h>

#pragma comment(lib, "ws2_32.lib")

bool make_nonblocking(SOCKET sock)
{
u_long mode = 1;
return ioctlsocket(sock, FIONBIO, &mode) != SOCKET_ERROR;
}

int recv_to(SOCKET sock, char* buff, int len, int flags, unsigned int tout)
{
DWORD start = GetTickCount();
int ret = recv(sock, buff, len, flags);
while(ret == -1 && WSAGetLastError() == WSAEWOULDBLOCK)
{
Sleep(10);
if(GetTickCount() - start > tout)
{
SetLastError(WSAETIMEDOUT);
return -1;
}
ret = recv(sock, buff, len, flags);
}
return ret;
}

int main()
{
WSADATA wsd;
if(WSAStartup(0x0202, &wsd) == 0)
{
SOCKET sock =socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(sock != INVALID_SOCKET)
{
sockaddr_in sa; memset(&sa, 0, sizeof(sockaddr_in));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = inet_addr("127.0.0.1");
sa.sin_port = htons(99);

if(connect(sock, (sockaddr*)&sa, sizeof(sockaddr_in)) != SOCKET_ERROR)
{
if(make_nonblocking(sock))
{
char buff[33]; memset(buff, 0, sizeof(buff));
int ret = recv_to(sock, buff, 32, 0, 5000);
printf("ret=%i\n", ret);
printf("err=%i\n", WSAGetLastError());
}
closesocket(sock);
}
}

WSACleanup();
}
getchar();
return 0;
}

Link to comment
Share on other sites

Absolut orice model inafara de cel dat original ca default cand folosesti ori Winsock ori UNIX sockets este blocking.

Cele de mai jos sunt non-blocking. Exemple gasesti pe tot netul - dar fi atent - bad practice vor fi in toate. Citeste manualul official pentru a nu face aceleasi greseli ca si altii...

ioctlsocket() e functia care schimba socket mode-ul manual.

Windows:

select & polling

WSAAsyncSelect

WSAAsyncEvent

Overlapped Events

Overlapped Routines

I/O Completion Ports

Linux:

Select

Epoll

AIO

Select merge mult mai bine pe Linux in comparatie cu alte systeme, dar Epoll e recomandat.

Pe Windows - daca nu vrei sa te faci de tot rahatul - IOCP sau Overlapped.

Edited by Comunistul
Link to comment
Share on other sites

@compile, da, intr-adevar doar de un recv() cu timeout aveam nevoie, exemplul tau ar parea ca se potriveste perfect. O sa ii fac o proba acum.

Multumesc celor care au postat.

Daca nu trec prea multe zile, o sa postez solutia scrisa de mine, pentru future refferences.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...