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); }
Вот что я считаю, вероятно, происходит.
harris@ics.uci.edu
, но, возможно, меньше. harris@ic
. strcmp
, который ничего не соответствует, поэтому возвращается в начало цикла. s.uci.edu
в buffer
, тем самым перезаписывая его . 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)
будут работать нормально, но другие более понятны при работе с сокетами и позволяют указывать другие флаги, например, заглядывать в байты, находящиеся в настоящее время в сокете, или ждать до тех пор, пока все запрошенные вами байты доступны перед возвратом.