как исправить цикл while в server.c и client.c

server.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; } 

client.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; } 

Я новичок в c, и я пишу server.c и client.c. Проблема моего кода в том, что я не могу заставить программу продолжать вводить ввод, пока я не введу «+++», чтобы выйти. Правильный вывод показан ниже:

клиентский терминал:

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

серверный терминал:

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

в моем коде, когда я вхожу «harris@ics.uci.edu» в клиентский терминал, он делает следующее:

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

и он больше не принимает никаких данных.

Что-то не так в цикле while? может кто-нибудь помочь мне исправить это? Заранее спасибо.

Немногие вещи:

В цикле клиента вы выполняете write и read в сокете. Но ваш сервер никогда не пишет в этот сокет (нет вызова на сервере, только read ). В результате ваш клиент блокируется при read . Вот почему вы не можете ввести больше …

В общем, вам нужно проверить, сколько вы написали и продолжать писать до завершения (необходим цикл).

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

То же самое касается чтения из сокета:

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

Вот что я считаю, вероятно, происходит.

  1. Клиент отправляет несколько fragmentов данных. Возможно, все строки harris@ics.uci.edu , но, возможно, меньше.
  2. Сервер читает несколько fragmentов этого, скорее всего, меньше полной строки, например, harris@ic .
  3. Сервер выполняет strcmp , который ничего не соответствует, поэтому возвращается в начало цикла.
  4. Сервер читает оставшуюся часть письма, скажем s.uci.edu в buffer , тем самым перезаписывая его .
  5. Опять же, это ничего не значит, поэтому сервер снова возвращается к вершине цикла while.
  6. Сервер зависает на вызове read , ожидая данных от клиента. Поскольку клиент ждет ответа, он застрял в собственном запросе на read . … И больше ничего не происходит.

Здесь есть две основные проблемы. Во-первых, сокеты TCP – это просто streamи байтов, и когда вы читаете данные из них, ОС больше не поддерживает их. Теперь вы должны обрабатывать любые ранее или частично прочитанные данные, если вам нужно. Во-вторых, ОС часто передает (как отправку, так и прием) меньшее количество байтов, чем вы запрашиваете. В то время как вы просите, чтобы была отправлена ​​полная строка harris@ics.uci.edu , только часть этого может быть отправлена, или только часть этого может быть прочитана с другой стороны.

Это означает для вас две вещи. Всегда важно проверять количество прочитанных / записанных данных в любое время, когда вы вызываете read(2) или write(2) , но это имеет решающее значение для сетевого взаимодействия. Убедитесь, что вы читаете / записываете столько, сколько вам нужно (полный адрес электронной почты в этом случае), прежде чем переходить к, например, в ожидании ответа.

Во-вторых, вам нужен способ определения полных сообщений и буферизации частичных сообщений. В том, что у вас есть, как это принято в большинстве текстовых протоколов обмена сообщениями, новая строка \n является вашим разделителем. Поэтому вместо одного вызова для read(2) на сервере вам нужно что-то вроде этого (pseduocode):

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

После того, как вы получите новую строку, обработайте полное сообщение, но не выбрасывайте лишние байты, которые вы прочитали из следующего сообщения. Сохраните их и добавьте следующие байты, прочитанные из сокета, и т. Д.

РЕДАКТИРОВАТЬ:

Обратите внимание, что обычно лучше использовать recv(2) и send(2) при работе с сокетами. Системные вызовы read(2) / write(2) будут работать нормально, но другие более понятны при работе с сокетами и позволяют указывать другие флаги, например, заглядывать в байты, находящиеся в настоящее время в сокете, или ждать до тех пор, пока все запрошенные вами байты доступны перед возвратом.