cómo arreglar el bucle while en server.c y client.c

servidor.c

#include  #include  #include  #include  #include  #include  #include  #include  #include  void error(char *msg) { perror(msg); exit(1); } int main(int argc, char *argv[]) { int sockfd, newsockfd, portno, clilen; char buffer[256]; struct sockaddr_in serv_addr, cli_addr; int n; char *result1 = "Ian G. Harris"; char *result2 = "Joe Smith"; char *result3 = "Jane Smith"; if (argc < 2) { fprintf(stderr,"ERROR, no port provided\n"); exit(1); } sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { error("ERROR opening socket"); } bzero((char *) &serv_addr, sizeof(serv_addr)); portno = atoi(argv[1]); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(portno); if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error("ERROR on binding"); listen(sockfd,5); clilen = sizeof(cli_addr); newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0) { error("ERROR on accept"); } while (strcmp(buffer, "+++") != 0) { bzero(buffer,256); n = read(newsockfd,buffer,255); if (n < 0) error("ERROR reading from socket"); printf("Address server started\n"); if (strcmp(buffer, "harris@ics.uci.edu\n") == 0) { printf("%s\n", result1); } else if(strcmp(buffer, "joe@cnn.com\n") == 0) { printf("%s\n", result2); } else if(strcmp(buffer, "jane@slashdot.org\n")==0) { printf("%s\n", result3); } } return 0; } 

cliente.c

 #include  #include  #include  #include  #include  #include  #include  #include  #include  void error(char *msg) { perror(msg); exit(0); } int main(int argc, char *argv[]) { int sockfd, portno, n; struct sockaddr_in serv_addr; struct hostent *server; char buffer[256]; if (argc < 3) { fprintf(stderr,"usage %s hostname port\n", argv[0]); exit(0); } portno = atoi(argv[2]); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); serv_addr.sin_port = htons(portno); if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))  "); bzero(buffer,256); fgets(buffer,255,stdin); n = write(sockfd,buffer,strlen(buffer)); if (n < 0) error("ERROR writing to socket"); bzero(buffer,256); n = read(sockfd,buffer,255); if (n < 0) error("ERROR reading from socket"); printf("%s\n",buffer); } return 0; } 

Soy nuevo en c y estoy escribiendo un server.c y client.c. El problema de mi código es que no puedo hacer que el progtwig siga tomando entradas hasta que ingrese “+++” para salir. La salida correcta se muestra a continuación:

terminal de cliente:

 > harris@ics.uci.edu Ian G. Harris > joe@cnn.com Joe > 

terminal de servidor:

 Address server started harris@ics.uci.edu joe@cnn.com 

en mi código, cuando ingreso “harris@ics.uci.edu” en el terminal del cliente, hace lo siguiente:

 > harris@ics.uci.edu (empty line) 

Y ya no toma ninguna entrada.

¿Hay algo mal en el bucle while? ¿Puede alguien ayudarme a arreglarlo? Gracias por adelantado.

Pocas cosas:

En el bucle del cliente, haces una write y una read en el socket. Pero su servidor nunca escribe en ese socket (no hay llamada de write en el servidor, solo read ). Como resultado, su cliente se bloquea en la llamada de read . Por eso no puedes entrar más …

En general, debe verificar cuánto escribió y seguir escribiendo hasta que termine (se necesita un ciclo).

 int n = 0; while (n != strlen(buffer){ n += write(sockfd,&buffer[n],strlen(buffer)-n); } 

Lo mismo ocurre con la lectura de un socket:

 int n = 0; while (n != strlen(buffer){ n += read(sockfd,&buffer[n],strlen(buffer)-n); } 

Esto es lo que creo que es probable que esté sucediendo.

  1. El cliente envía parte de los datos. Posiblemente toda la cadena harris@ics.uci.edu , pero posiblemente menos.
  2. El servidor lee algo de esto, probablemente menos que la cadena completa, por ejemplo, harris@ic .
  3. El servidor realiza el strcmp , que no coincide con nada, por lo que vuelve a la parte superior del bucle.
  4. El servidor lee el rest del correo electrónico, diga s.uci.edu en el buffer , y lo sobrescribe .
  5. De nuevo, esto no coincide con nada, por lo que el servidor vuelve a la parte superior del bucle while de nuevo.
  6. El servidor se cuelga en la llamada de read , esperando los datos del cliente. Debido a que el cliente está esperando una respuesta, está bloqueado en su propia llamada de read . … Y no pasa nada más.

Hay dos problemas principales aquí. Primero, los sockets TCP son solo flujos de bytes, y cuando lees datos, el sistema operativo ya no los mantiene. Ahora se espera que maneje cualquier dato anterior o parcialmente leído si lo necesita. Y segundo, el sistema operativo a menudo transmite (enviando y recibiendo) menos bytes de los que solicita. Mientras solicita que se harris@ics.uci.edu cadena completa harris@ics.uci.edu , solo se puede enviar una parte de eso, o solo una parte de eso se puede leer en el otro lado.

Esto significa dos cosas para ti. Siempre es importante verificar la cantidad de datos leídos / escritos cada vez que llamas read(2) o write(2) , pero es crucial en la red. Asegúrese de leer / escribir tanto como necesite (el correo electrónico completo en este caso) antes de continuar, por ejemplo, esperando una respuesta.

La segunda cosa es que necesita alguna forma de delinear mensajes completos y almacenar mensajes parciales. En lo que tienes, como es común en muchos protocolos de mensajería basados ​​en texto, la línea nueva \n es tu delimitador. Entonces, en lugar de una sola llamada para read(2) en el servidor, necesitas algo como esto (pseduocode):

 while newline not in data: data += read(sockfd, ...) 

Una vez que reciba su nueva línea, procese el mensaje completo, pero no tire los bytes adicionales que haya leído en el siguiente mensaje. Manténgalos alrededor y agregue los siguientes bytes leídos del socket a ellos, y así sucesivamente.

EDITAR:

Tenga en cuenta que, por lo general, es mejor utilizar recv(2) y send(2) cuando se trabaja con sockets. Las llamadas al sistema de read(2) / write(2) funcionarán bien, pero las otras son más claras cuando se trabaja con sockets y le permiten especificar otras banderas, por ejemplo, echar un vistazo a los bytes que están actualmente en el socket o esperar hasta Todos los bytes que solicite están disponibles antes de regresar.