/* Пример сервера, работающего с sendfile. порядок использования: server [port] Copyright (C) 2003 Jeff Tranter. Это программное обеспечение может свободно распространяться и/или изменяться в соответствии с условиями GNU General Public License версии 2 или более поздней, опубликованной Free Software Foundation. Это программное обеспечение распространяется в надежде, что оно будет вам полезно, но БЕЗ КАКИХ ЛИБО ГАРАНТИЙ. За пояснениями обращайтесь к тексту GNU General Public License. Вместе с данным программным обеспечением должен распространяться текст GNU General Public License, если это не так -- сообщите в Free Software Foundation, Inc., по адресу 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char **argv) { int port = 1234; /* номер порта */ int sock; /* дескриптор сокета */ int desc; /* файловый дескриптор для сокета */ int fd; /* дескриптор исходного файла */ struct sockaddr_in addr; /* параметры сокета для bind*/ struct sockaddr_in addr1; /* параметры сокета для accept */ int addrlen; /* аргументы для accept */ struct stat stat_buf; /* аргументы для fstat */ off_t offset = 0; /* смещение в исходном файле */ char filename[PATH_MAX]; /* имя исходного файла */ int rc; /* код завершения системного вызова */ /* проверить наличие аргументов командной строки -- номер порта*/ if (argc == 2) { port = atoi(argv[1]); if (port <= 0) { fprintf(stderr, "неверный номер порта: %s\n", argv[1]); exit(1); } } else if (argc != 1) { fprintf(stderr, "порядок исползования: %s [port]\n", argv[0]); exit(1); } /* создать сокет */ sock = socket(AF_INET, SOCK_STREAM, 0); if (sock == -1) { fprintf(stderr, "не могу создать сокет: %s\n", strerror(errno)); exit(1); } /* заполнить структуру сокета */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(port); /* "повесить" сокет на порт */ rc = bind(sock, (struct sockaddr *)&addr, sizeof(addr)); if (rc == -1) { fprintf(stderr, "не могу привязать сокет: %s\n", strerror(errno)); exit(1); } /* ожидать соединение с клиентом */ rc = listen(sock, 1); if (rc == -1) { fprintf(stderr, "ошибка ожидания соединения: %s\n", strerror(errno)); exit(1); } while (1) { /* ожидать соединение с клиентом */ desc = accept(sock, (struct sockaddr *) &addr1, &addrlen); if (desc == -1) { fprintf(stderr, "ошибка приема соединения: %s\n", strerror(errno)); exit(1); } /* получить имя файла от клиента */ rc = recv(desc, filename, sizeof(filename), 0); if (rc == -1) { fprintf(stderr, "ошибка приема имени файла: %s\n", strerror(errno)); exit(1); } /* вставить завершающий null и удалить все символы \r и \n из имени файла */ filename[rc] = '\0'; if (filename[strlen(filename)-1] == '\n') filename[strlen(filename)-1] = '\0'; if (filename[strlen(filename)-1] == '\r') filename[strlen(filename)-1] = '\0'; /* завершить работу "сервера", если имя файла == "quit" */ if (strcmp(filename, "quit") == 0) { fprintf(stderr, "принята команда quit, завершение работы\n"); break; } fprintf(stderr, "принят запрос на передачу файла %s\n", filename); /* открыть запрошенный файл */ fd = open(filename, O_RDONLY); if (fd == -1) { fprintf(stderr, "не могу открыть файл '%s': %s\n", filename, strerror(errno)); exit(1); } /* получить размер файла */ fstat(fd, &stat_buf); /* выполнить передачу файла */ offset = 0; rc = sendfile (desc, fd, &offset, stat_buf.st_size); if (rc == -1) { fprintf(stderr, "ошибка sendfile: %s\n", strerror(errno)); exit(1); } if (rc != stat_buf.st_size) { fprintf(stderr, "файл передан не полностью: передано %d из %d байт\n", rc, (int)stat_buf.st_size); exit(1); } /* закрыть исходный файл */ close(fd); /* закрыть дескриптор сокета */ close(desc); } /* закрыть сокет */ close(sock); return 0; }