Foro de elhacker.net

Programación => Programación C/C++ => Mensaje iniciado por: mester en 9 Noviembre 2015, 12:32 pm



Título: Abrir multiples conexiones Sockets C
Publicado por: mester en 9 Noviembre 2015, 12:32 pm
Hola.
Estoy introduciéndome en el mundo de los sockets en Linux y haciendo tanto cliente como servidor quise iniciar mi primer chat. Hasta ahí bien, pero ahora lo que quiero es que el servidor del chat pueda soportar varias conexiones (que hacerlo, lo hace) pero que lea también de éstas. Es decir, este "chat" solo funciona por turnos jeje. Escribo mi código:
Servidor:
Código
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<string.h>
  4. #include<unistd.h>
  5. #include<sys/types.h>
  6. #include<sys/socket.h>
  7. #include<netinet/in.h>
  8. #include<netdb.h>
  9. int main(int argc, char **argv){
  10. if(argc<2){
  11. printf("%s <puerto>\n",argv[0]);
  12. return 1;
  13. }
  14. int con_ser,con_cli,puerto;
  15. int I;
  16. socklen_t clilen;
  17. char *buffer;
  18. struct sockaddr_in cliente;
  19. struct sockaddr_in servidor;
  20. con_ser=socket(AF_INET,SOCK_STREAM,0);
  21. if(con_ser<0){
  22. printf("Error creando el socket\n");
  23. close(con_ser);
  24. return 1;
  25. }
  26. bzero((char *)&servidor,sizeof(servidor));
  27. puerto=atoi(argv[1]);
  28. servidor.sin_family = AF_INET;
  29. servidor.sin_port = htons(puerto);
  30. servidor.sin_addr.s_addr = INADDR_ANY;
  31. I=bind(con_ser,(struct sockaddr *)&servidor,sizeof(servidor));
  32. if(I<0){
  33. printf("Error al asignar el puerto\n");
  34. close(con_ser);
  35. return 1;
  36. }
  37. listen(con_ser,3);
  38. clilen = sizeof(cliente);
  39. con_cli=accept(con_ser,(struct sockaddr *)&cliente,&clilen);
  40. if(con_cli<0){
  41. printf("Error en la transaccion\n");
  42. close(con_ser);
  43. return 1;
  44. }
  45. buffer=calloc(220,sizeof(char));
  46. do{
  47. I=read(con_cli,buffer,220);
  48. if(I<0){
  49. printf("Error recibiendo información\n");
  50. close(con_ser);
  51. return 1;
  52. }
  53. if(strcmp(buffer,"101001001")!=0)
  54. printf("%s",buffer);
  55. else{
  56. printf("EOF\n");
  57. break;
  58. }
  59. free(buffer);
  60. buffer=calloc(220,sizeof(char));
  61. printf("%s: ",getlogin());
  62. fgets(buffer,220,stdin);
  63. I=write(con_cli,buffer,220);
  64. if(I<0){
  65.                        printf("Error enviando información\n");
  66.                        close(con_ser);
  67.                        return 1;
  68.                }
  69. }while(1);
  70. return 0;
  71. }
  72.  

Cliente:
Código
  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<string.h>
  4. #include<unistd.h>
  5. #include<sys/types.h>
  6. #include<sys/socket.h>
  7. #include<netinet/in.h>
  8. #include<netdb.h>
  9. #define RED     "\x1b[31m"
  10. #define GREEN   "\x1b[32m"
  11. #define YELLOW  "\x1b[33m"
  12. #define BLUE    "\x1b[34m"
  13. #define MAGENTA "\x1b[35m"
  14. #define CYAN    "\x1b[36m"
  15. #define RESET   "\x1b[0m"
  16. int cmp(char *s1, char *s2, char *s3){
  17. int ret = 0;
  18. strcat(s3,": ");
  19. strcat(s3,s2);
  20. while(!(ret=*(unsigned char *)s1 - *(unsigned char *)s3) && *s3)
  21. ++s1, ++s3;
  22. if(ret<0)
  23. ret=-1;
  24. if(ret > 0)
  25. ret=1;
  26. return ret;
  27. }
  28. int main(int argc, char **argv){
  29. if(argc<3){
  30. printf(YELLOW"%s <host> <puerto>\n"RESET,argv[0]);
  31. return 1;
  32. }
  33. int conexion,puerto,i;
  34. char *frase;
  35. char *buffer;
  36. struct hostent *server;
  37. struct sockaddr_in cliente;
  38. server=gethostbyname(argv[1]);
  39. if(server==NULL){
  40. printf(RED"Host erróneo, introduce el host\n"RESET);
  41. return 1;
  42. }
  43. conexion=socket(AF_INET,SOCK_STREAM,0);
  44. puerto=atoi(argv[2]);
  45. cliente.sin_family = AF_INET;
  46. cliente.sin_port = htons(puerto);
  47. bcopy((char *)server->h_addr,(char *)&cliente.sin_addr.s_addr,sizeof(server->h_length));
  48. i=connect(conexion,(struct sockaddr *)&cliente,sizeof(cliente));
  49. if(i<0){
  50. printf("Error conectando con el host\n");
  51. close(conexion);
  52. return 1;
  53. }
  54. printf(YELLOW"Escribe "RED"\"EOF\""RESET" para salir\n"RESET);
  55. do{
  56. buffer=calloc(220,sizeof(char));
  57. if(buffer==NULL){
  58. printf("No se ha podido reservar memoria\n");
  59. close(conexion);
  60. return 1;
  61. }
  62. frase=calloc(200,sizeof(char));
  63. if(frase==NULL){
  64. printf("No se ha podido reservar memoria\n");
  65.                        close(conexion);
  66.                        return 1;
  67.                }
  68. printf(YELLOW"%s: "RESET,getlogin());
  69. fgets(frase,200,stdin);
  70. strcat(buffer,getlogin());
  71. strcat(buffer,": ");
  72. strcat(buffer,frase);
  73. if(cmp(buffer,"EOF\n",getlogin())==0){
  74. write(conexion,"101001001",10);
  75. break;
  76. }
  77. i=write(conexion,buffer,220);
  78. if(i<0){
  79. printf(RED"Error al enviar los datos\n"RESET);
  80. break;
  81. }
  82. free(frase);
  83. i=read(conexion,buffer,220);
  84. if(i<0){
  85.                        printf(RED"Error al recibir los datos\n"RESET);
  86.                        break;
  87.                }
  88. printf("%s",buffer);
  89. }while(1);
  90. close(conexion);
  91. free(buffer);
  92. return 0;
  93. }
  94.  

Se agradece de antemano


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: ivancea96 en 9 Noviembre 2015, 13:35 pm
Los sockets abiertos, los conservas en un array. Luego, basta iterar por cada socket del array, y leer en caso de que haya bytes que leer, y enviar datos si es necesario.

Deberías estructurar tu programa. Crea funciones para hacer el código legible.


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: mester en 10 Noviembre 2015, 00:10 am
Los sockets abiertos, los conservas en un array. Luego, basta iterar por cada socket del array, y leer en caso de que haya bytes que leer, y enviar datos si es necesario.

Deberías estructurar tu programa. Crea funciones para hacer el código legible.
Supongo que entiendo lo que dices, pero no sé aplicarlo. ¿puedes explicármelo de diferente manera si es posible?
Se agradece


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: ivancea96 en 10 Noviembre 2015, 09:17 am
Te pongo un ejemplo práctico:

Código
  1. socket *sockets;
  2. listener li;
  3.  
  4. crearArray(&sockets);
  5. inicializarSocketDeEscucha(li);
  6.  
  7. while(true){
  8.    socket sock;
  9.    sock = nuevoCliente(listener);
  10.    if(sock) añadirSocket(&sockets, sock);
  11.    porCadaSocket -i-{
  12.        escucharYResponder(sockets[i]);
  13.    }
  14. }

En fin, es un esquema, con funciones que creo que entiendes lo que hacen. En bucle, haces estas acciones:
-1: Encuentras nuevos clientes si los hay.
-2: Escuchas y respondes a cada cliente. Si por ejemplo un cliente te envía un mensaje de chat, reenvías ese mensaje a todos los demás clientes.


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: mester en 10 Noviembre 2015, 09:55 am
Te pongo un ejemplo práctico:

Código
  1. socket *sockets;
  2. listener li;
  3.  
  4. crearArray(&sockets);
  5. inicializarSocketDeEscucha(li);
  6.  
  7. while(true){
  8.    socket sock;
  9.    sock = nuevoCliente(listener);
  10.    if(sock) añadirSocket(&sockets, sock);
  11.    porCadaSocket -i-{
  12.        escucharYResponder(sockets[i]);
  13.    }
  14. }

En fin, es un esquema, con funciones que creo que entiendes lo que hacen. En bucle, haces estas acciones:
-1: Encuentras nuevos clientes si los hay.
-2: Escuchas y respondes a cada cliente. Si por ejemplo un cliente te envía un mensaje de chat, reenvías ese mensaje a todos los demás clientes.
El problema es que cuando espero una conexión entrante con la función 'accept()' el programa se detiene esperando una conexión entrante. Y con el cliente, cuando le indico que reciba con 'recv()' hasta que no recibe información no puedes seguir escribiendo.
Agradezco el ejemplo de codigo, ahora mismo me pongo a organizarlo.


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: ivancea96 en 10 Noviembre 2015, 10:53 am
Los sockets pueden ser "bloqueantes" o "no bloqueantes". En el caso que comentas, probablemente sea bloquenate. Para ponerlo "non-blocking", no te puedo ayudar, que no utilizo unix. Busca por ahí, y encontrarás.

De todos modos, tal ocmo los tienes, otra opción es tener un thread para leer del servidor, y luego otro thread para los sockets ya abiertos (o un thread por socket, tú verás).

Claro que, para recv, me parece más cómodo un socket no bloqueante. Lo dicho, echa un vistazo para ver cómo cambiar.

En caso de sockets de Windows, se haría así:
Código
  1. u_long block = 1 // 1 or 0, bloquing or non blocking;
  2. ioctlsocket(sock, FIONBIO, &block);


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: mester en 10 Noviembre 2015, 17:11 pm
Los sockets pueden ser "bloqueantes" o "no bloqueantes". En el caso que comentas, probablemente sea bloquenate. Para ponerlo "non-blocking", no te puedo ayudar, que no utilizo unix. Busca por ahí, y encontrarás.

De todos modos, tal ocmo los tienes, otra opción es tener un thread para leer del servidor, y luego otro thread para los sockets ya abiertos (o un thread por socket, tú verás).

Claro que, para recv, me parece más cómodo un socket no bloqueante. Lo dicho, echa un vistazo para ver cómo cambiar.

En caso de sockets de Windows, se haría así:
Código
  1. u_long block = 1 // 1 or 0, bloquing or non blocking;
  2. ioctlsocket(sock, FIONBIO, &block);

He estado probando a ponerlo non-blocking, de momento funciona, ahora, no sabría como desarrollar el programa para que tanto cliente como servidor puedan enviar mensajes sin parar, y el otro los reciba, es decir, que me gustaría que el fgets() no bloquease el programa a la espera de una entrada de datos, para hacerlo más fácil, sino, se acumulan todos los mensajes. Escribo las funciones de la conexión:

Código
  1. int conectar(int sock, struct sockaddr_in client){
  2.        char *frase;
  3.        char *buffer;
  4.        if(connect(sock,(struct sockaddr *)&client,sizeof(client))<0)
  5.                error(1,inet_ntoa(client.sin_addr));
  6.        else
  7.                printf("Conectando con %s:%d\n\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
  8.        printf("\t\t\t\t%s\n",inet_ntoa(client.sin_addr));
  9.        fcntl(sock,F_SETFL,O_NONBLOCK);
  10.        frase=(char *)calloc(200,sizeof(char));
  11.        buffer=(char *)calloc(220,sizeof(char));
  12.        while(1){
  13.                printf("%s: ",getlogin());
  14.                if(leer(sock)!=0)
  15.                        continue;
  16.                fgets(frase,200,stdin);
  17.                if(strcmp(frase,"EOF\n")==0){
  18.                        free(frase);
  19.                        free(buffer);
  20.                        break;
  21.                }
  22.                buffer=cmp(frase,getlogin());
  23.                if(send(sock,buffer,220,0)<0)
  24.                        error(2,inet_ntoa(client.sin_addr));
  25.        }
  26.        free(frase);
  27.        free(buffer);
  28. return 0;
  29. }
  30. int leer(int conexion){
  31.        int c;
  32.        char *buffer;
  33.        buffer=(char *)calloc(200,sizeof(char));
  34.        if(recv(conexion,buffer,200,0)>0){
  35.                printf("%s",buffer);
  36.                c=0;
  37.        }
  38.        else
  39.                c=1;
  40. return c;
  41. }
  42.  

Agradezco tu ayuda, me es muy útil para desarrollar mi programa.


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: ivancea96 en 10 Noviembre 2015, 18:32 pm
Para hacerlo con consola, y querer leer de consola, lo puedes hacer con 2 threads, uno para leer la consola, y otro para trabajar el/los sockets.

De todos modos, ten en cuenta algo: si recibes un mensaje mientras escribes, la consola escribirá sobre lo que tú estás escribiendo. Para practicar está bien, pero bueno.

Para eso, lo dicho, threads.


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: mester en 11 Noviembre 2015, 11:03 am
Para hacerlo con consola, y querer leer de consola, lo puedes hacer con 2 threads, uno para leer la consola, y otro para trabajar el/los sockets.

De todos modos, ten en cuenta algo: si recibes un mensaje mientras escribes, la consola escribirá sobre lo que tú estás escribiendo. Para practicar está bien, pero bueno.

Para eso, lo dicho, threads.

Vale ya lo tengo, ahora necesito saber cómo matar un fork. He estado buscando, pero con kill(pid,SIGKILL); no me funciona, te muestro el codigo:
 (MODIFICADO)
Ya lo he hecho para que funcione. Funciona mal, porque mato directamente el proceso, pero bueno, ya lo mejoraré. Posteo aquí el codigo tanto de cliente como de servidor.

Cliente:
Código
  1. #include<stdio.h>
  2. #include<wait.h>
  3. #include<signal.h>
  4. #include<sys/types.h>
  5. #include<string.h>
  6. #include<stdlib.h>
  7. #include<unistd.h>
  8. #include<arpa/inet.h>
  9. #include<sys/socket.h>
  10. #include<netinet/in.h>
  11. #include<netdb.h>
  12. #include<fcntl.h>
  13. void usage(const char *arg){
  14. printf("%s <host> <puerto>\n",arg);
  15. exit(1);
  16. }
  17. void error(int codigo, const char *err){
  18. switch(codigo){
  19. case 0: printf("La dirección del Host no es válida\n"); break;
  20. case 1: printf("Error conectando con el host %s\n",err); break;
  21. case 2: printf("Error enviando los datos a %s\n",err); break;
  22. }
  23. exit(1);
  24. }
  25. char *cmp(char *palabra, char *nombre){
  26.        char *mem=(char *)calloc(220,sizeof(char));
  27.        strcat(mem,nombre);
  28.        strcat(mem,": ");
  29.        strcat(mem,palabra);
  30. return mem;
  31. }
  32. void leer(int);
  33. int escribir(int,struct sockaddr_in);
  34. int conectar(int, struct sockaddr_in);
  35. int main(int argc, char **argv){
  36. if(argc<3)
  37. usage(argv[0]);
  38. int conexion, puerto;
  39. struct sockaddr_in cliente;
  40. struct hostent *servidor;
  41. servidor=gethostbyname(argv[1]);
  42. if(servidor==NULL)
  43. error(0," ");
  44. conexion=socket(AF_INET,SOCK_STREAM,0);
  45. puerto=atoi(argv[2]);
  46. cliente.sin_family=AF_INET;
  47. cliente.sin_port=htons(puerto);
  48. bcopy((char *)servidor->h_addr,(char *)&cliente.sin_addr,sizeof(servidor->h_length));
  49. conectar(conexion, cliente);
  50. send(conexion,"78421687541295",15,0);
  51. close(conexion);
  52. return 0;
  53. }
  54. int conectar(int sock, struct sockaddr_in client){
  55. int c;
  56. int id;
  57. int estado;
  58. if(connect(sock,(struct sockaddr *)&client,sizeof(client))<0)
  59. error(1,inet_ntoa(client.sin_addr));
  60. else
  61. printf("Conectando con %s:%d\n\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port));
  62. printf("Escribe \"EOF\" para salir\n");
  63. printf("\t\t\t\t%s\n",inet_ntoa(client.sin_addr));
  64. fcntl(sock,F_SETFL,O_NONBLOCK);
  65. id=fork();
  66. if(id==0){
  67. while(1){
  68. leer(sock);
  69. sleep(1);
  70. }
  71. }
  72. while(1){
  73. c=escribir(sock,client);
  74. if(c==1)
  75. break;
  76. }
  77. kill(id,SIGKILL);
  78. return 0;
  79. }
  80. void leer(int conexion){
  81. char *cadena;
  82. cadena=(char *)calloc(220,sizeof(char));
  83. if(recv(conexion,cadena,220,0)>0)
  84. printf("\n%s",cadena);
  85. else
  86. free(cadena);
  87. }
  88. int escribir(int conexion,struct sockaddr_in client){
  89. char *buffer=(char *)calloc(220,sizeof(char));
  90. char *cadena=(char *)calloc(200,sizeof(char));
  91. printf("%s: ",getlogin());
  92. fgets(cadena,200,stdin);
  93. buffer=cmp(cadena,getlogin());
  94. if(strcmp(cadena,"EOF\n")==0)
  95. return 1;
  96. if(send(conexion,buffer,220,0)<0)
  97. error(2,inet_ntoa(client.sin_addr));
  98. free(buffer);
  99. free(cadena);
  100. return 0;
  101. }
  102.  

Servidor:
Código
  1. #include<stdio.h>
  2. #include<wait.h>
  3. #include<sys/types.h>
  4. #include<string.h>
  5. #include<stdlib.h>
  6. #include<unistd.h>
  7. #include<arpa/inet.h>
  8. #include<netinet/in.h>
  9. #include<netdb.h>
  10. #include<fcntl.h>
  11. void usage(const char *arg){
  12. printf("%s <puerto>\n",arg);
  13. exit(1);
  14. }
  15. char *cmp(char *palabra, char *nombre){
  16.        char *mem=(char *)calloc(220,sizeof(char));
  17.        strcat(mem,nombre);
  18.        strcat(mem,": ");
  19.        strcat(mem,palabra);
  20. return mem;
  21. }
  22. void escribir(int);
  23. int recibir(int);
  24. int escuchar(int, struct sockaddr_in);
  25. int main(int argc, char **argv){
  26. if(argc<2)
  27. usage(argv[0]);
  28. int conexion_servidor, puerto;
  29. char *buffer;
  30. struct sockaddr_in servidor;
  31. puerto=atoi(argv[1]);
  32. conexion_servidor=socket(AF_INET,SOCK_STREAM,0);
  33. servidor.sin_family=AF_INET;
  34. servidor.sin_port=htons(puerto);
  35. servidor.sin_addr.s_addr=INADDR_ANY;
  36. escuchar(conexion_servidor,servidor);
  37. printf("Hasta luego\n");
  38. close(conexion_servidor);
  39. return 0;
  40. }
  41. int escuchar(int conexion_servidor, struct sockaddr_in servidor){
  42. struct sockaddr_in cliente;
  43. int c;
  44. int id;
  45. int conexion_cliente;
  46. int clilong;
  47. if(bind(conexion_servidor,(struct sockaddr *)&servidor,sizeof(servidor))<0){
  48.                printf("Error. El puerto está en uso\n");
  49.                close(conexion_servidor);
  50.                return 1;
  51.        }
  52.        listen(conexion_servidor,5);
  53.        clilong=sizeof(cliente);
  54.        printf("Escuchando en el puerto %d\n",htons(servidor.sin_port));
  55.        conexion_cliente=accept(conexion_servidor,(struct sockaddr *)&cliente,&clilong);
  56.        if(conexion_cliente<0){
  57.                printf("Error en la asociacion con el host %s\n",inet_ntoa(cliente.sin_addr));
  58.                close(conexion_servidor);
  59.                return 1;
  60.        }
  61.        else
  62.                printf("Conectado con %s:%d\n",inet_ntoa(cliente.sin_addr),ntohs(servidor.sin_port));
  63. fcntl(conexion_cliente,F_SETFL,O_NONBLOCK);
  64. id=fork();
  65. if(id==0){
  66. while(1){
  67. sleep(1);
  68. c=recibir(conexion_cliente);
  69. if(c==1)
  70. break;
  71. }
  72. }
  73. while(c!=1)
  74. escribir(conexion_cliente);
  75. kill(id,SIGKILL);
  76. return 0;
  77. }
  78. int recibir(int conexion){
  79. int c=0;
  80. char *buffer=(char *)calloc(220,sizeof(char));
  81. if(recv(conexion,buffer,220,0)>0){
  82. if(strcmp(buffer,"78421687541295")!=0)
  83. printf("\n%s",buffer);
  84. else
  85. c=1;
  86. }
  87. free(buffer);
  88. return c;
  89. }
  90. void escribir(int conexion){
  91. char *buffer=(char *)calloc(220,sizeof(char));
  92. char *cadena=(char *)calloc(200,sizeof(char));
  93. printf("SERVIDOR: ");
  94. fgets(cadena,200,stdin);
  95. buffer=cmp(cadena,"SERVIDOR");
  96. if(send(conexion,buffer,220,0)<0)
  97. printf("Error enviando la información\n");
  98. }
  99.  


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: ivancea96 en 11 Noviembre 2015, 16:10 pm
Matarlo es muy bruto. En vez de eso, cambia el while(1) por una variable que compartan, y cuando quieras que se detenga, pones esa variable a 0, por ejemplo.


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: mester en 11 Noviembre 2015, 17:00 pm
Matarlo es muy bruto. En vez de eso, cambia el while(1) por una variable que compartan, y cuando quieras que se detenga, pones esa variable a 0, por ejemplo.
xdd Ya, matar es un poco bestial.
Una cuestión para aádir al programa. ¿Existe manera alguna de que el programa no consuma mucho sin necesidad de ponerle un sleep(), no sé vaciando memoria o algo?


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: ivancea96 en 11 Noviembre 2015, 17:22 pm
Consume CPU, no memoria, si no le pones sleep en algunos bucles.

Evidentemente los bucles de algoritmos no se pueden moderar con sleeps, por cuestiones de eficiencia. Pero en este caso, si lo que se hace es esperar mensajes, no importa 10 ms de retardo en leer, y a cambio, logrará sacarle un montón de peso a la CPU.

Con esto quiero decir: pon sleeps si es necesario, no hacen mal.


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: mester en 11 Noviembre 2015, 17:49 pm
Consume CPU, no memoria, si no le pones sleep en algunos bucles.

Evidentemente los bucles de algoritmos no se pueden moderar con sleeps, por cuestiones de eficiencia. Pero en este caso, si lo que se hace es esperar mensajes, no importa 10 ms de retardo en leer, y a cambio, logrará sacarle un montón de peso a la CPU.

Con esto quiero decir: pon sleeps si es necesario, no hacen mal.
Cierto, fallo mio la mala asignación del termino. Pero, ¿hay manera alguna para hacer que no consuma mucha CPU, sin necesidad de sleeps? Por ejemplo programas como dd en linux que están continuamente copiando datos de una lado a otro, no consumen mucho. ¿Cómo hacen esto? Me he descargado el codigo, pero xd no tengo mucha idea, he visto que utiliizan punteros y ya.


Título: Re: Abrir multiples conexiones Sockets C
Publicado por: ivancea96 en 11 Noviembre 2015, 19:21 pm
Ten también en cuenta, que cualquierespera, ya sea espera para que el disco duro lea o escriba, ya sea espera a que se reciban datos de un socket, etc, a efectos prácticos hace en parte las veces de un sleep.