Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.57/37: Рейтинг темы: голосов - 37, средняя оценка - 4.57
32 / 32 / 3
Регистрация: 25.05.2014
Сообщений: 1,137
1

Свой мини веб-сервер

07.04.2016, 21:12. Показов 7701. Ответов 4
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
У меня задание по предмету написать простейший веб-сервер, работающий по протоколу http. Я прочел гайд Биджа, состряпал код, который запускает сервер и ждет подключений, и когда получает, отправляет Hello, World. Вот код:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*
** server.c -- a stream socket server demo
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
 
#define PORT "3491"  // the port users will be connecting to
 
#define BACKLOG 10   // how many pending connections queue will hold
 
void sigchld_handler(int s)
{
    // waitpid() might overwrite errno, so we save and restore it:
    int saved_errno = errno;
 
    while(waitpid(-1, NULL, WNOHANG) > 0);
 
    errno = saved_errno;
}
 
 
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }
 
    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
 
int main(void)
{
    int sockfd, new_fd;  // listen on sock_fd, new connection on new_fd
    struct addrinfo hints, *servinfo, *p;
    struct sockaddr_storage their_addr; // connector's address information
    socklen_t sin_size;
    struct sigaction sa;
    int yes=1;
    char s[INET6_ADDRSTRLEN];
    int rv;
    char* response;
    response = "Hello world";
 
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; // use my IP
 
    if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        return 1;
    }
 
    // loop through all the results and bind to the first we can
    for(p = servinfo; p != NULL; p = p->ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,
                p->ai_protocol)) == -1) {
            perror("server: socket");
            continue;
        }
 
        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                sizeof(int)) == -1) {
            perror("setsockopt");
            exit(1);
        }
 
        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
            close(sockfd);
            perror("server: bind");
            continue;
        }
 
        break;
    }
 
    freeaddrinfo(servinfo); // all done with this structure
 
    if (p == NULL)  {
        fprintf(stderr, "server: failed to bind\n");
        exit(1);
    }
 
    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }
 
    sa.sa_handler = sigchld_handler; // reap all dead processes
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }
 
    printf("server: waiting for connections...\n");
 
    while(1) {  // main accept() loop
        sin_size = sizeof their_addr;
        new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
        if (new_fd == -1) {
            perror("accept");
            continue;
        }
 
        inet_ntop(their_addr.ss_family,
            get_in_addr((struct sockaddr *)&their_addr),
            s, sizeof s);
        printf("server: got connection from %s\n", s);
 
        if (!fork()) { // this is the child process
            close(sockfd); // child doesn't need the listener
            if (send(new_fd, response, 11, 0) == -1)
                perror("send");
            close(new_fd);
            exit(0);
        }
        close(new_fd);  // parent doesn't need this
    }
 
    return 0;
}
Сообщение Hello World появляется в браузере. все хорошо. Потом я захотел эмулировать ответ от сервера, т.е. чтобы возвращалось все как должно быть и чтобы бразуер понял что надо интерпретировать html - документ. Поэтому я переписал переменную response:
C
1
response = "HTTP/1.1 200 OK\nServer: nginx\nDate: Thu, 07 Apr 2016 16:54:55 GMT\nContent-Type: text/html\nConnection: close\nX-Powered-By: PHP/5.5.9-1ubuntu4.4\n<!DOCTYPE html>\n<HTML>Hello</HTML>";
Размер в send соответственно указал равным кол-ву символов в этой строке. Но бразуер выдает ошибку при попытке подключения, а если посмотреть ответ от сервера в консоли браузера, то там по нулям заголовки и тд. Почему так происходит?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
07.04.2016, 21:12
Ответы с готовыми решениями:

AVR мини веб сервер
Доброго времени суток! Товарищи помогите пожалуйста совладать с программным обеспечением данного...

Друзья я хочу сделать свой веб сервер и хочу узнать можно обойтись без ОС Centos
Apache MysQl PHP+CMS все настроено теперь осталось вывести его в инет Что нужно делать? Настроить...

Мини веб браузер
Всем привет. Подскажите пожалуйста есть ли в java готовый компонент для отображения веб страниц или...

Мини сервер до $100
Здравствуйте, Хочу приобрести какой-нибудь mini PC и админить его по SSH. Что-то типа Raspberry...

4
Почетный модератор
11525 / 4320 / 448
Регистрация: 12.06.2008
Сообщений: 12,412
07.04.2016, 22:01 2
Лучший ответ Сообщение было отмечено danek130995 как решение

Решение

Заголовок от данных должен отделяться двумя переводами строки. И для перевода строки по стандарту надо использовать \r\n.
X-Powered-By: PHP/5.5.9-1ubuntu4.4\n<!DOCTYPE html>
замените на
Код
X-Powered-By: PHP/5.5.9-1ubuntu4.4\n\n<!DOCTYPE html>
и все \n замените на \r\n... и должно работать.
1
32 / 32 / 3
Регистрация: 25.05.2014
Сообщений: 1,137
07.04.2016, 22:21  [ТС] 3
Humanoid, спасибо большое, заработало. Дело было в этих двух пробелах. Кстати, без \r тоже работает. А еще вопрос:почему иногда, через раз, проскакивает в браузере ошибка все равно:Соединение было сброшено. Через раз-другой. Почему так?
0
Почетный модератор
11525 / 4320 / 448
Регистрация: 12.06.2008
Сообщений: 12,412
07.04.2016, 22:27 4
Цитата Сообщение от danek130995 Посмотреть сообщение
Кстати, без \r тоже работает.
Работает на всех браузерах, какие я пробовал... но по стандарту нужны виндовые переводы строки (только в заголовках... сами данные могут быть с любыми переводами строк).

Цитата Сообщение от danek130995 Посмотреть сообщение
почему иногда, через раз, проскакивает в браузере ошибка все равно:Соединение было сброшено. Через раз-другой. Почему так?
Я плохо знаком с форками... подозреваю, что у них общие сокеты и если основной процесс закрывает new_fd, то подключение закрывается... и всё зависит от того, что раньше произойдёт: выполнится send() или close() (просто версия... точно не знаю). Но выглядит очень странно... как минимум напрашивается else перед close(new_fd) ... но как я сказал, я с форками плохо знаком, поэтому не могу сейчас точно ответить.
1
153 / 148 / 66
Регистрация: 20.02.2014
Сообщений: 556
08.04.2016, 11:44 5
man fork
* The child inherits copies of the parent's set of open file descriptors. Each file descriptor in the child refers to the same open file description (see open(2)) as the corresponding file descriptor in the parent. This
means that the two descriptors share open file status flags, current file offset, and signal-driven I/O attributes (see the description of F_SETOWN and F_SETSIG in fcntl(2)).
0
08.04.2016, 11:44
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
08.04.2016, 11:44
Помогаю со студенческими работами здесь

Подбираю веб сервер для веб ресурса
Здравствуйтеhttp://www.onno.ru/ru/witem/34472/- Смотрю на это http://www.onno.ru/ru/witem/50186/...

Дешевый мини сервер на основе Pogoplug
Сейчас все работает на стареньком компьютере 1Ghz + 512Ram. Там бежит 5 сайтов, общая посещаемость...

Мини-сервер для 2-3 рабочих столов
Привет всем, прошу помочь с выбором комплектующих: Необходимо собрать наиболее компактный...

Мини-сервер под Win/Mac
Всем привет. Решил сменить NSA на что-то более отвечающее моим интересам. Ранее увлекался этой...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru