socket servidor funcion cliente c sockets select bsd

funcion - socket en c++ cliente servidor linux



Usando select() para sockets no bloqueantes (3)

El problema es que cuando los ejecuto, no pasa nada.

El verdadero problema es que la gente ha estado pegando cosas de Beej durante años sin entenderlo. Es por eso que realmente no me gusta esa guía; da grandes bloques de código sin realmente explicarlos en detalle.

No estás leyendo nada y no estás enviando nada; sin fgets, scanf, cin, etc. Esto es lo que haría:

FD_SET(sock, &read_flags); FD_SET(STDIN_FILENO, &read_flags); /* .. snip .. */ if(FD_ISSET(STDIN_FILENO, &read_flags)) { fgets(out, len, stdin); }

Esto monitoreará stdin y leerá el formulario cuando la entrada esté disponible; luego, cuando el socket es grabable ( FD_ISSET(sock, &write_flags) ) enviará el búfer.

Estoy tratando de usar la función de selección para tener E / S sin bloqueo entre un servidor y 1 cliente (no más) donde la comunicación fluye bien (puede enviar en cualquier momento y la otra recibirá sin esperar para enviar). Encontré un tutorial con algún código e intenté adaptarlo al mío. Esto es lo que tengo -

Servidor

#define PORT "4950" #define STDIN 0 struct sockaddr name; void set_nonblock(int socket) { int flags; flags = fcntl(socket,F_GETFL,0); assert(flags != -1); fcntl(socket, F_SETFL, flags | O_NONBLOCK); } // get sockaddr, IPv4 or IPv6: void *get_in_addr(struct sockaddr *sa) { if (sa->sa_family == AF_INET) return &(((struct sockaddr_in*)sa)->sin_addr); return &(((struct sockaddr_in6*)sa)->sin6_addr); } int main(int agrc, char** argv) { int status, sock, adrlen, new_sd; struct addrinfo hints; struct addrinfo *servinfo; //will point to the results //store the connecting address and size struct sockaddr_storage their_addr; socklen_t their_addr_size; fd_set read_flags,write_flags; // the flag sets to be used struct timeval waitd; // the max wait time for an event int sel; // holds return value for select(); //socket infoS memset(&hints, 0, sizeof hints); //make sure the struct is empty hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; //tcp hints.ai_flags = AI_PASSIVE; //use local-host address //get server info, put into servinfo if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo error: %s/n", gai_strerror(status)); exit(1); } //make socket sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol); if (sock < 0) { printf("/nserver socket failure %m", errno); exit(1); } //allow reuse of port int yes=1; if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { perror("setsockopt"); exit(1); } //unlink and bind unlink("127.0.0.1"); if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) { printf("/nBind error %m", errno); exit(1); } freeaddrinfo(servinfo); //listen if(listen(sock, 5) < 0) { printf("/nListen error %m", errno); exit(1); } their_addr_size = sizeof(their_addr); //accept new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size); if( new_sd < 0) { printf("/nAccept error %m", errno); exit(1); } set_nonblock(new_sd); cout<<"/nSuccessful Connection!"; char* in = new char[255]; char* out = new char[255]; int numSent; int numRead; while(1) { waitd.tv_sec = 10; FD_ZERO(&read_flags); FD_ZERO(&write_flags); FD_SET(new_sd, &read_flags); if(strlen(out) != 0) FD_SET(new_sd, &write_flags); sel = select(new_sd+1, &read_flags, &write_flags, (fd_set*)0, &waitd); if(sel < 0) continue; //socket ready for reading if(FD_ISSET(new_sd, &read_flags)) { FD_CLR(new_sd, &read_flags); memset(&in, 0, sizeof(in)); if(recv(new_sd, in, sizeof(in), 0) <= 0) { close(new_sd); break; } else cout<<"/n"<<in; } //end if ready for read //socket ready for writing if(FD_ISSET(new_sd, &write_flags)) { FD_CLR(new_sd, &write_flags); send(new_sd, out, strlen(out), 0); memset(&out, 0, sizeof(out)); } } //end while cout<<"/n/nExiting normally/n"; return 0; }

Cliente (básicamente lo mismo, solo menos una llamada de aceptación) -

#define PORT "4950" struct sockaddr name; void set_nonblock(int socket) { int flags; flags = fcntl(socket,F_GETFL,0); assert(flags != -1); fcntl(socket, F_SETFL, flags | O_NONBLOCK); } // get sockaddr, IPv4 or IPv6: void *get_in_addr(struct sockaddr *sa) { if (sa->sa_family == AF_INET) return &(((struct sockaddr_in*)sa)->sin_addr); return &(((struct sockaddr_in6*)sa)->sin6_addr); } int main(int agrc, char** argv) { int status, sock, adrlen; struct addrinfo hints; struct addrinfo *servinfo; //will point to the results fd_set read_flags,write_flags; // the flag sets to be used struct timeval waitd; // the max wait time for an event int sel; // holds return value for select(); memset(&hints, 0, sizeof hints); //make sure the struct is empty hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; //tcp hints.ai_flags = AI_PASSIVE; //use local-host address //get server info, put into servinfo if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo error: %s/n", gai_strerror(status)); exit(1); } //make socket sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol); if (sock < 0) { printf("/nserver socket failure %m", errno); exit(1); } if(connect(sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) { printf("/nclient connection failure %m", errno); exit(1); } cout<<"/nSuccessful connection!"; set_nonblock(sock); char* out = new char[255]; char* in = new char[255]; int numRead; int numSent; while(1) { waitd.tv_sec = 10; FD_ZERO(&read_flags); FD_ZERO(&write_flags); FD_SET(sock, &read_flags); if(strlen(out) != 0) FD_SET(sock, &write_flags); sel = select(sock+1, &read_flags, &write_flags, (fd_set*)0, &waitd); if(sel < 0) continue; //socket ready for reading if(FD_ISSET(sock, &read_flags)) { FD_CLR(sock, &read_flags); memset(&in, 0, sizeof(in)); if(recv(sock, in, sizeof(in), 0) <= 0) { close(sock); break; } else cout<<"/n"<<in; } //end if ready for read //socket ready for writing if(FD_ISSET(sock, &write_flags)) { FD_CLR(sock, &write_flags); send(sock, out, strlen(out), 0); memset(&out, 0, sizeof(out)); } } //end while cout<<"/n/nExiting normally/n"; return 0; }

El problema es que cuando los ejecuto, no pasa nada. Puedo escribir en uno y presionar enter y nada aparece en la otra pantalla (y viceversa). Esa no es toda la información que debo depurar y este es mi primer intento real de usar select, así que pensé que tal vez no estaba enterado de algo simple. Si algo puede ser visto como incorrecto o extraño, por favor indíquelo, cualquier ayuda es apreciada.


Tengo el programa funcionando correctamente ahora.

servidor -

#define PORT "4950" #define STDIN 0 struct sockaddr name; void set_nonblock(int socket) { int flags; flags = fcntl(socket,F_GETFL,0); assert(flags != -1); fcntl(socket, F_SETFL, flags | O_NONBLOCK); } // get sockaddr, IPv4 or IPv6: void *get_in_addr(struct sockaddr *sa) { if (sa->sa_family == AF_INET) return &(((struct sockaddr_in*)sa)->sin_addr); return &(((struct sockaddr_in6*)sa)->sin6_addr); } int main(int agrc, char** argv) { int status, sock, adrlen, new_sd; struct addrinfo hints; struct addrinfo *servinfo; //will point to the results //store the connecting address and size struct sockaddr_storage their_addr; socklen_t their_addr_size; fd_set read_flags,write_flags; // the flag sets to be used struct timeval waitd = {10, 0}; // the max wait time for an event int sel; // holds return value for select(); //socket infoS memset(&hints, 0, sizeof hints); //make sure the struct is empty hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; //tcp hints.ai_flags = AI_PASSIVE; //use local-host address //get server info, put into servinfo if ((status = getaddrinfo("127.0.0.1", PORT, &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo error: %s/n", gai_strerror(status)); exit(1); } //make socket sock = socket(servinfo->ai_family, servinfo->ai_socktype, servinfo->ai_protocol); if (sock < 0) { printf("/nserver socket failure %m", errno); exit(1); } //allow reuse of port int yes=1; if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) { perror("setsockopt"); exit(1); } //unlink and bind unlink("127.0.0.1"); if(bind (sock, servinfo->ai_addr, servinfo->ai_addrlen) < 0) { printf("/nBind error %m", errno); exit(1); } freeaddrinfo(servinfo); //listen if(listen(sock, 5) < 0) { printf("/nListen error %m", errno); exit(1); } their_addr_size = sizeof(their_addr); //accept new_sd = accept(sock, (struct sockaddr*)&their_addr, &their_addr_size); if( new_sd < 0) { printf("/nAccept error %m", errno); exit(1); } //set non blocking set_nonblock(new_sd); cout<<"/nSuccessful Connection!/n"; char in[255]; char out[255]; memset(&in, 0, 255); memset(&out, 0, 255); int numSent; int numRead; while(1) { FD_ZERO(&read_flags); FD_ZERO(&write_flags); FD_SET(new_sd, &read_flags); FD_SET(new_sd, &write_flags); FD_SET(STDIN_FILENO, &read_flags); FD_SET(STDIN_FILENO, &write_flags); sel = select(new_sd+1, &read_flags, &write_flags, (fd_set*)0, &waitd); //if an error with select if(sel < 0) continue; //socket ready for reading if(FD_ISSET(new_sd, &read_flags)) { //clear set FD_CLR(new_sd, &read_flags); memset(&in, 0, 255); numRead = recv(new_sd, in, 255, 0); if(numRead <= 0) { printf("/nClosing socket"); close(new_sd); break; } else if(in[0] != ''/0'') cout<<"/nClient: "<<in; } //end if ready for read //if stdin is ready to be read if(FD_ISSET(STDIN_FILENO, &read_flags)) fgets(out, 255, stdin); //socket ready for writing if(FD_ISSET(new_sd, &write_flags)) { //printf("/nSocket ready for write"); FD_CLR(new_sd, &write_flags); send(new_sd, out, 255, 0); memset(&out, 0, 255); } //end if } //end while cout<<"/n/nExiting normally/n"; return 0; }

El cliente es básicamente el mismo ... la única diferencia es la falta de escuchar y aceptar.


Solo quiero agregar que el ejemplo anterior puede no funcionar como se espera en Linux. En Linux waitd puede ser modificado por select. Entonces, para Linux, la espera debe ser reescrita antes de seleccionar.

Consulte la sección "tiempo de espera" en la página de manual para seleccionar.