#c #sockets
Вопрос:
Моя цель-реализовать простую передачу данных с сервера на клиент. Проблема в том, что клиент большую часть времени не может считывать данные с сервера (это работает только иногда), даже если сервер сообщает, что передача прошла успешно.
сервер.c
#include lt;stdio.hgt; #include lt;stdlib.hgt; #include lt;string.hgt; #include lt;sys/socket.hgt; #include lt;netinet/in.hgt; #include lt;unistd.hgt; #define PORT 8080 void main() { int sock = socket(AF_INET, SOCK_STREAM, 0), option = 1; struct sockaddr_in address; socklen_t addrlen = sizeof(address); char buffer[1024] = {0}; char source_file[] = "lt;pathgt;/something.txt"; char fname[] = "something.txt"; address.sin_family = AF_INET; address.sin_addr.s_addr = INADDR_ANY; address.sin_port = htons(PORT); setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, amp;option, sizeof(option)); if(bind(sock, (struct sockaddr*) amp;address, sizeof(address)) == -1){ perror("Could not bind to address"); return; } if(listen(sock, 5) == -1) { perror("Error while listening to connections"); return; } int new_socket = accept(sock, (struct sockaddr*) amp;address, amp;addrlen); if(new_socket == -1){ perror("Error connecting to client"); exit(EXIT_FAILURE); } else printf("Connected to clientn"); // first send the filename if(send(new_socket, fname, sizeof(fname), 0) == -1){ perror("Error while sending file"); return; } printf("Sending file %snn", source_file); FILE* f = fopen(source_file, "r"); // send the contents of the file while(fgets(buffer, sizeof(buffer), f)){ printf("Sending %s", buffer); if(send(new_socket, buffer, strlen(buffer), 0) == -1) perror("Error while sendingn"); else printf("Successfully sentnn"); memset(buffer, 0, sizeof(buffer)); } printf("File transfer completen"); fclose(f); }
клиент.c
#include lt;stdio.hgt; #include lt;stdlib.hgt; #include lt;string.hgt; #include lt;sys/socket.hgt; #include lt;arpa/inet.hgt; #include lt;unistd.hgt; #define PORT 8080 void main() { int sock = socket(AF_INET, SOCK_STREAM, 0); long val; struct sockaddr_in address; char buffer[1024] = {0}; address.sin_family = AF_INET; address.sin_port = htons(PORT); if(inet_pton(AF_INET, "127.0.0.1", amp;address.sin_addr) == -1){ perror("Invalid IP value"); exit(EXIT_FAILURE); } if(connect(sock,(struct sockaddr*) amp;address, sizeof(address)) == -1){ perror("Connection Error"); exit(EXIT_FAILURE); } else printf("Connected to servern"); // Get file name from server if(read(sock, buffer, sizeof(buffer)) == -1){ perror("Could not read filename from server"); exit(EXIT_FAILURE); } printf("Receiving file %sn", buffer); FILE *f = fopen(buffer, "w"); // printf("%ld", read(sock, buffer, sizeof(buffer))); while((val = read(sock, buffer, sizeof(buffer)))){ if (val == 0) break; if (val == -1) { perror("Error reading the content"); break; } printf("Read returned %ldn", val); printf("Received %s", buffer); fputs(buffer, f); memset(buffer, 0, sizeof(buffer)); } printf("File transfer completen"); fclose(f); }
Sample text file for data transfer
Hello there! Nice to meet you. This is a text file. Bye Bye :) Have a good day.
Выполнение со стороны сервера
$ cc ./server.c -o server $ ./server Connected to client Sending file /home/username/Documents/something.txt Sending Hello there! Successfully sent Sending Nice to meet you. Successfully sent Sending This is a text file. Successfully sent Sending Bye Bye :) Successfully sent Sending Have a good day. Successfully sent File transfer complete
Это был вывод, который я получил со стороны сервера. Это странно, потому что на стороне клиента я не получил никакого сообщения
$ cc ./client.c -o client $ ./client Connected to server Receiving file something.txt File transfer complete
Цикл while на стороне клиента вообще не выполнялся (поскольку данные в буфере не печатались), а функция чтения не возвращала -1, иначе было бы отображено правильное сообщение.
Этот точный клиентский код работает только иногда, а иногда нет. В чем здесь проблема?
Комментарии:
1.
send(new_socket, buffer, strlen(buffer), 0)
отправляет строку без нулевого терминатора.2.
read(sock, buffer, sizeof(buffer))
не проверяет, сколько байтов он получил. Обратите внимание, что данные recv не обязательно соответствуют границам отправки.3. такого рода заявление также должно быть у клиента:
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, amp;option, sizeof(option));
4. относительно:
printf("Read returned %ldn", val);
поскольку это сообщение не было выведено, этот вызов:while((val = read(sock, buffer, sizeof(buffer)))){
вернул 0