BSD Sockets – ¿Cómo usar sockets no bloqueantes?

Estoy tratando de usar sockets TCP no bloqueantes. El problema es que todavía están bloqueando. El código está abajo.

código de servidor

struct sockaddr name; char buf[80]; void set_nonblock(int socket) { int flags; flags = fcntl(socket,F_GETFL,0); assert(flags != -1); fcntl(socket, F_SETFL, flags | O_NONBLOCK); } int main(int agrc, char** argv) { int sock, new_sd, adrlen; //sock is this socket, new_sd is connection socket name.sa_family = AF_UNIX; strcpy(name.sa_data, "127.0.0.1"); adrlen = strlen(name.sa_data) + sizeof(name.sa_family); //make socket sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { printf("\nBind error %m", errno); exit(1); } //unlink and bind unlink("127.0.0.1"); if(bind (sock, &name, adrlen) < 0) printf("\nBind error %m", errno); //listen if(listen(sock, 5) < 0) printf("\nListen error %m", errno); //accept new_sd = accept(sock, &name, (socklen_t*)&adrlen); if( new_sd < 0) { cout<<"\nserver accept failure "<<errno; exit(1); } //set nonblock set_nonblock(new_sd); char* in = new char[80]; std::string out = "Got it"; int numSent; int numRead; while( !(in[0] == 'q' && in[1] == 'u' && in[2] == 'i' && in[3] == 't') ) { //clear in buffer for(int i=0;i>out; cin.get(); //if we typed something, send it if(strlen(out.c_str()) > 0) { numSent = send(new_sd, out.c_str(), strlen(out.c_str()), 0); cout<<"\n"<<numSent< 0) cout<<"\nData read from client - "<<in; } //end while cout<<"\nExiting normally\n"; return 0; } 

codigo del cliente –

 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); } int main(int agrc, char** argv) { int sock, new_sd, adrlen; sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) { printf("\nserver socket failure %m", errno); exit(1); } //stuff for server socket name.sa_family = AF_UNIX; strcpy(name.sa_data, "127.0.0.1"); adrlen = strlen(name.sa_data) + sizeof(name.sa_family); if(connect(sock, &name, adrlen) < 0) { printf("\nclient connection failure %m", errno); exit(1); } cout<<"\nSuccessful connection\n"; //set nonblock set_nonblock(sock); std::string out; char* in = new char[80]; int numRead; int numSent; while(out.compare("quit")) { //clear in for(int i=0;i 0) cout<<"\nData read from server - "<<in; cout<>out; cin.get(); //if we typed something, send it if(strlen(out.c_str())) { numSent = send(sock, out.c_str(), strlen(out.c_str()), 0); cout<<"\n"<<numSent<<" bytes sent"; } } //end while cout<<"\nExiting normally\n"; return 0; } 

Cada vez que lo ejecuto, el servidor todavía espera que envíe algo antes de leer y enviar lo que el cliente ha enviado. Quiero que el servidor o el cliente puedan enviar el mensaje tan pronto como lo escriba, y que el otro lea y emita el mensaje en ese momento. Pensé que los sockets no bloqueantes eran la respuesta, pero ¿tal vez solo estoy haciendo algo mal?

Además, estaba usando un archivo en lugar de mi dirección 127.0.0.1 como datos de sockaddr. Si no es así como se debe usar correctamente, siéntase libre de decirlo (funcionó como funcionó anteriormente con un archivo, así que lo guardé así).

Cualquier ayuda es apreciada.

Cada vez que lo ejecuto, el servidor todavía espera que envíe algo antes de leer y enviar lo que el cliente ha enviado.

Bueno, así es como lo escribiste. Bloqueas IO desde stdin, y luego y solo entonces envías / recibes.

 cin>>out; cin.get(); 

Además, está utilizando un socket local (AF_UNIX) que crea un archivo especial en su sistema de archivos para la comunicación entre procesos: este es un mecanismo diferente al IP, y definitivamente no es TCP como indica su pregunta. Supongo que podría nombrar el archivo 127.0.0.1 , pero eso realmente no tiene sentido e implica confusión por su parte, porque es una dirección IP de bucle de retorno. Querrás usar AF_INET para IP.

Para una excelente guía de inicio sobre redes de Unix, recomiendo http://beej.us/guide/bgnet/

Si desea que la visualización de los mensajes recibidos sea independiente de sus declaraciones cin, bifurque () el proceso por separado para manejar el IO de su red, o use un hilo separado.

Usted podría estar interesado en seleccionar (). En mi opinión, los sockets no bloqueantes suelen ser un truco, y el uso adecuado de select () o poll () es generalmente un diseño mucho mejor y más flexible (y más portátil). tratar

hombre select_tut

para más información.

Enfoque general para un servidor TCP donde desea manejar muchas conexiones al mismo tiempo:

  • hacer que la toma de escucha no bloquee
  • agregarlo para select(2) o poll(2) leer el conjunto de eventos
  • ingrese select(2) / poll(2) loop
  • en el despertador, compruebe si es la toma de escucha, luego
    • accept(2)
    • comprobar si hay un error (el cliente podría haber abandonado el bash de conexión por ahora)
    • hacer que el socket del cliente recién creado no se bloquee, agregarlo al conjunto de eventos de sondeo
  • de lo contrario, si es uno de los sockets del cliente.
    • consume entrada, procesalo
    • EAGAIN código de error EAGAIN : no es realmente un error, pero indica que no hay entrada ahora
    • si se leyó cero bytes: conexión cerrada del cliente, close(2) socket del cliente, elimínelo del conjunto de eventos
  • reiniciar el conjunto de eventos (omitir esto es un error común con select(2) )
  • repite el bucle

El lado del cliente es un poco más sencillo ya que solo tienes un socket. Sin embargo, las aplicaciones avanzadas, como los navegadores web que manejan muchas conexiones, a menudo no connect(2) sin locking.

Creo que tienes que configurar el no locking antes (es decir, obtener el zócalo y luego configurar el no locking)

También compruebe que el fcntl para configurarlo realmente funcionó

Si desea una E / S sin locking, desea utilizar Seleccionar. Puede configurarlo con stdin como uno de los sockets que está escuchando, junto con los sockets del cliente (solo agregue el descriptor de archivo 1, que es stdin, al fd_set).

http://beej.us/guide/bgnet/output/html/multipage/advanced.html

Recomendaría leer lo que tiene que decir Beej acerca de seleccionar. Parece un poco intimidante, pero es realmente útil y fácil de usar si te tomas un poco de tiempo para rodearlo.

Intereting Posts