Re[25]: C++ listen tcp socket
От: Handler Украина  
Дата: 10.10.11 09:35
Оценка:
Вот это да! Почему все так просто оказалось? -lboost_system решил проблему. Не перестаю удивлять окружающих своей тупостью, впрочем, и себя тоже.
Спасибо.
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[26]: C++ listen tcp socket
От: yurror Россия  
Дата: 10.10.11 11:53
Оценка:
Здравствуйте, Handler, Вы писали:

H>Вот это да! Почему все так просто оказалось? -lboost_system решил проблему. Не перестаю удивлять окружающих своей тупостью, впрочем, и себя тоже.

H>Спасибо.
Хватит насиловать человека boost'ом.
Он в трех соснах (listen bind accept) сишных функциях заблудился и понятия не имеет ни про синхронность асинхронность многопоточность и т.п.
Ему Стивенса читать надо
стивенс unix взаимодействие процессов
стивенс unix разработка сетевых приложений
+ man epoll
Когда осилит — будет писать обёртки на С++ когда их осилит почитает про boost.asio
Re[27]: C++ listen tcp socket
От: Handler Украина  
Дата: 11.10.11 09:32
Оценка:
К сожалению, у меня со стивенсом не срослось — первый же пример не скомпилился
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[28]: C++ listen tcp socket
От: Аноним  
Дата: 13.10.11 06:44
Оценка:
Как ни прискорбно — но с boost у меня тоже не срослось.
Итак, вернемся к самописному варианту tcp-сервера.
Как утверждает Стивенс (и не зря утверждает), "сервер" начинает слушать протокол и порт, который мы ему "натравили":
listen();
И далее принимает(или "засыпает", если очередь входящих сообщений пуста) входящие запросы от "клиента" (в нашем случае — веб-браузера):
accept();

(Дальше мои мысли)
Следовательно, как только accept() вернул нам валидный дескриптор:
if ( (session=accept(socket, buf, buf_len))!=-1 ) {/*valid handler*/}
мы можем создавать дочерний поток(процесс), который обработает запрос и завершится:
listen();
for (;;) {
accept();
if ( (session=accept(socket, buf, buf_len))!=-1 ) {
if(!fork()) {/*child*/do smth; exit(0);}
else        {/*parent*/ close(session);}
}
}


Такая схема не работает.
Подскажите, пожалуйста, в каком месте нарушена логика?
Re[29]: C++ listen tcp socket
От: Handler Украина  
Дата: 13.10.11 06:58
Оценка:
Простите, поторопился я с выводами — представленная мной схема оказалась вполне работоспособной.

Теперь скажите мне, почему session закрывается родителем?
Я, конечно, ноль в многопоточности, однако из прочитанной мной литературы о процессах сделал вывод, что с момента
fork()
и родитель, и его потомок начинают работать одновременно в одном и том же адресном пространстве (за последнее не ручаюсь). Как же потомок сможет читать/писать в session, если родитель, согласно логике программы, сразу же закроет дескриптор?
Подскажите, пожалуйста, в каком месте нарушена логика?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[30]: C++ listen tcp socket
От: yurror Россия  
Дата: 13.10.11 08:07
Оценка:
Здравствуйте, Handler, Вы писали:

H>Простите, поторопился я с выводами — представленная мной схема оказалась вполне работоспособной.


H>Теперь скажите мне, почему session закрывается родителем?

H>Я, конечно, ноль в многопоточности, однако из прочитанной мной литературы о процессах сделал вывод, что с момента
H>fork()
H>и родитель, и его потомок начинают работать одновременно в одном и том же адресном пространстве (за последнее не ручаюсь). Как же потомок сможет читать/писать в session, если родитель, согласно логике программы, сразу же закроет дескриптор?
H>Подскажите, пожалуйста, в каком месте нарушена логика?
открой для себя man
разные процессы живут в разных адресных пространствах
fork создаёт новый процесс
если хочешь одно адресное пространство тебе надо создавать поток(нить, thread) в том же процессе.
Вот мой эксперемент 3х-летеней давновсти. Дыр куча — не проект а решето

http_buffer.c
#include <http_buffer.h>

#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>

/* HTTP Buffer Block Functions */

http_buffer_block *http_make_buffer_block(size_t length, const char *data)
{
    http_buffer_block *res = (http_buffer_block *)malloc(sizeof(http_buffer_block));
    res->data = (char*)malloc(res->length = length);
    memcpy(res->data, data, length);
    res->next = NULL;
    return res;
}

size_t http_buffer_block_cat(http_buffer_block *block, char *dst, size_t length)
{
    size_t size;
    char *buf;
    
    size = length <= block->length ? length : block->length;
    memcpy(dst, block->data, size);
    
    buf = block->data;
    
    block->data = (char*)malloc(block->length -= size);
    memcpy(block->data, buf+size, block->length);
    
    free(buf);
    return size;
}

void http_free_buffer_blocks(http_buffer_block *block)
{
    if (block) {
        http_free_buffer_blocks(block->next);
        if (block->data)
            free(block->data);
        free(block);
    }
}

http_buffer_block *http_free_buffer_block(http_buffer_block *block)
{
    http_buffer_block *res = NULL;
    if (block) {
        res = block->next;
        if (block->data)
            free(block->data);
        free(block);
    }
    return res;
}

/* HTTP BUffer Functions */

http_buffer* http_make_buffer(int fd)
{
    http_buffer* res = (http_buffer*)malloc(sizeof(http_buffer));
    res->fd = fd;
    res->first = NULL;
    res->last = NULL;
    return res;
}

void http_free_buffer(http_buffer* buf)
{
    if (buf) {
        http_free_buffer_blocks(buf->first);
        free(buf);
    }
}

void http_buffer_append(http_buffer* buf, size_t length, const char* str)
{
    if (length && str) {
        http_buffer_block *block = http_make_buffer_block(length, str);
        
        if (! buf->first)
            buf->first = buf->last = block;
        else {
            buf->last->next = block;
            buf->last = buf->last->next;
        }
    }
}

#define BUFSIZE 1024
int http_buffer_recv(http_buffer* buf)
{
    if (buf->fd != -1) {
        char recv_buf[BUFSIZE];
        int length = recv(buf->fd, recv_buf, BUFSIZE, 0);
        write(0, recv_buf, length);
        if (length > 0) {
            http_buffer_append(buf, length, recv_buf);
        }
        return length;
    }
    return -1;
}

size_t http_buffer_length(http_buffer* buf)
{
    size_t length = 0;
    if (buf) {
        http_buffer_block * next = buf->first;
        while (next) {
            length += next->length;
            next = next->next;
        }
    }
    return length;
}

char *http_buffer_readln(http_buffer* buf)
{
    char *pos;
    size_t length = 0;
    if (!(buf->first) && (http_buffer_recv(buf) < 0)) {
        pos = (char*)malloc(1);
        pos[0] = 0;
        return pos;
    }
    http_buffer_block *block = buf->first;
    while (! (pos = strstr(block->data, HTTP_ENDL))) {
        length += block->length;
        if (!(block->next) && (http_buffer_recv(buf) < 0)) {
            pos = (char*)malloc(1);
            pos[0] = 0;
            return pos;
        }
        block = block->next;
    }
    length += (pos - block->data) + strlen(HTTP_ENDL);
    pos = http_buffer_read(buf, length);
    pos[length-1] = 0;
    pos[length-2] = 0;
    return pos;
}

char *http_buffer_read(http_buffer* buf, size_t length)
{
    char *res;
    size_t len = http_buffer_length(buf);
    while (len < length) {
        int bytes = http_buffer_recv(buf);
        if (bytes < 0) {
            return NULL;
        }
        len += bytes;
    }
    res = (char*)malloc(length);
    len = 0;
    while (len < length) {
        http_buffer_block *first = buf->first;
        if (first->length <= (length-len)) {
            memcpy(res+len, first->data, first->length);
            len += first->length;
            buf->first = http_free_buffer_block(first);
        } else {
            len += http_buffer_block_cat(first, res+len, length-len);
        }
    }
    return res;
}

int http_buffer_send(http_buffer *buf, int fd)
{
    buf->fd = fd;
    while (buf->first) {
        char *pos = buf->first->data;
        size_t length = buf->first->length;
        while (length) {
            int s = send(buf->fd, pos, length, 0);
            if (s < 0) { return -1; }
            pos += s;
            length -= s;
        }
        write(0, buf->first->data, buf->first->length);
        buf->first = http_free_buffer_block(buf->first);
    }
    buf->last = NULL;
    return 0;
}


http.c
#include <http.h>

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

http_request* http_make_request(const char *method, const char *resource,
    const http_headers *headers, size_t data_length, const char *data)
{
    http_request* res = (http_request*)malloc(sizeof(http_request));
    if (method) {
        res->method = (char*)malloc(strlen(method));
        strcpy(res->method, method);
    } else res->method = NULL;
    
    if (resource) {
        res->resource = (char*)malloc(strlen(resource));
        strcpy(res->resource, resource);
    } else res->resource = NULL;
    
    if (headers) {
        size_t i;
        res->headers = (http_headers*)malloc(sizeof(http_headers));
        for (i = 0; i < headers->length; ++i) {
            http_string_pair *pair = headers->hdrs[i];
            http_headers_push_back(res->headers, pair);
        }
    } else res->headers = NULL;
    
    res->data_length = data_length;
    if (res->data_length) {
        res->data = (char*)malloc(data_length);
        memcpy(res->data, data, data_length);
    } else res->data = NULL;
    return res;
}

void http_free_request(http_request* request) {
    if (request) {
        if (request->method)
            free(request->method);

        if (request->resource)
            free(request->resource);

        if (request->headers)
            http_free_headers(request->headers);
        
        if (request->data)
            free(request->data);

        free(request);
    }
}

http_request *http_parse_request(http_buffer* request)
{
    char *line, buf1[100], buf2[1024];
    http_request *res = (http_request *)malloc(sizeof(http_request));

    line = http_buffer_readln(request);
    sscanf(line, "%s%s", buf1, buf2);
    free(line);

    res->method = (char*)malloc(strlen(buf1)+1);
    memcpy(res->method, buf1, strlen(buf1)+1);
    
    res->resource = (char*)malloc(strlen(buf2)+1);
    memcpy(res->resource, buf2, strlen(buf2)+1);

    res->headers = http_make_headers(NULL);
    line = http_buffer_readln(request);
    while (strlen(line)) {
        if (isspace(line[0])) {
            char* pos = line;
            while (*pos && isspace(*pos)) pos++;
            if (res->headers->length) {
                http_string_pair *pair = res->headers->hdrs[res->headers->length-1];
                pair->value = (char*)realloc(pair->value,
                        strlen(pair->value) + strlen(pos) + 2);
                strcat(pair->value, " ");
                strcat(pair->value, pos);
            }
        } else {
            http_string_pair *pair;
            char* pos = strstr(line, HTTP_HEADER_DELIMITER);
            *pos = 0;
            pair = http_make_pair(line, pos+strlen(HTTP_HEADER_DELIMITER));
            http_headers_push_back(res->headers, pair);
            http_free_pair(pair);
        }
        free(line);
        line = http_buffer_readln(request);
    }
    free(line);
    
    const char *str = http_headers_get_value(res->headers, "Content-Length");
    if (str) {
        res->data_length = strtoul(str, NULL, 10);
        res->data = http_buffer_read(request, res->data_length);
    } else {
        res->data_length = 0;
        res->data = NULL;
    }

    return res;
}

http_response* http_make_response(int code, const http_headers *headers,
    size_t data_length, const char *data)
{
    http_response* res = (http_response*)malloc(sizeof(http_response));
    res->code = code;
    
    if (headers) {
        size_t i;
        res->headers = http_make_headers(NULL);
        for (i = 0; i < headers->length; ++i) {
            http_string_pair *pair = headers->hdrs[i];
            http_headers_push_back(res->headers, pair);
        }
    } else res->headers = NULL;
    
    res->data_length = data_length;
    if (res->data_length) {
        res->data = (char*)malloc(data_length);
        memcpy(res->data, data, data_length);
    } else res->data = NULL;

    return res;
}

void http_free_response(http_response* response)
{
    if (response) {
        if (response->headers)
            http_free_headers(response->headers);
        
        if (response->data)
            free(response->data);
        free(response);
    }
}

static const http_code_table code_table[] = {
    {200, "OK"},
    {201, "Created"},
    {202, "Accepted"},
    {204, "No content"},
    {301, "Moved Permanently"},
    {302, "Moved Temporarily"},
    {304, "Not Modified"},
    {400, "Bad Request"},
    {401, "Unauthorized"},
    {403, "Forbidden"},
    {404, "Not Found"},
    {500, "Internal Server Error"},
    {501, "Not Implemented"},
    {502, "Bad Gateway"},
    {503, "Service Unavailable"},
    {0, NULL}
};

const char *http_get_string_code (int code) {
    size_t i;
    for (i = 0; code_table[i].code; ++i) {
        if ( code_table[i].code == code )
            return code_table[i].str;
    }
    return NULL;
}

http_buffer *http_assemble_response(const http_response* response)
{
    http_buffer *res_buf;
    char buf[100], *headers;
    res_buf = http_make_buffer(-1);
    
    if (! http_headers_get_value(response->headers, "Content-Length")) {
        sprintf(buf, "%d", response->data_length);
        http_string_pair *pair = http_make_pair("Content-Length", buf);
        http_headers_push_back(response->headers, pair);
        http_free_pair(pair);
    }

    sprintf(buf, "HTTP/1.1 %d %s%s", response->code,
          http_get_string_code(response->code), HTTP_ENDL);
    http_buffer_append(res_buf, strlen(buf), buf);
    
    headers = http_headers_to_text(response->headers);
    http_buffer_append(res_buf, strlen(headers), headers);
    free(headers);
    
    http_buffer_append(res_buf, strlen(HTTP_ENDL), HTTP_ENDL);
    http_buffer_append(res_buf, response->data_length, response->data);
    return res_buf;
}

http_headers *http_make_headers(http_string_pair *pairs)
{
    http_headers *res = (http_headers *)malloc(sizeof(http_headers));
    res->length = 0;
    res->hdrs = NULL;

    if (pairs) {
        while (pairs->key) {
            http_headers_push_back(res, pairs);
            pairs++;
        }
    }

    return res;
}

int http_headers_push_back(http_headers *headers, const http_string_pair *pair)
{
    if (headers && pair) {
        headers->length++;
        headers->hdrs = (http_string_pair **)realloc(headers->hdrs,
                sizeof(http_string_pair *) * headers->length);
        headers->hdrs[headers->length-1] = http_make_pair(pair->key, pair->value);
        return headers->length;
    }
    return -1;
}

const char *http_headers_get_value(http_headers *headers, const char* key)
{
    size_t i;
    for (i = 0; i < headers->length; ++i) {
        if (! strcasecmp(headers->hdrs[i]->key, key))
            return headers->hdrs[i]->value;
    }
    return NULL;
}

char *http_headers_to_text(http_headers *headers)
{
    char *res;
    size_t i, length;
    for(i = 0; i < headers->length; ++i) {
        length += strlen(headers->hdrs[i]->key) + strlen(HTTP_HEADER_DELIMITER) + 
            strlen(headers->hdrs[i]->value) + strlen(HTTP_ENDL);
    }
    res = (char*)malloc(length+1);
    res[0] = 0;
    for(i = 0; i < headers->length; ++i) {
        strcat(res, headers->hdrs[i]->key);
        strcat(res, HTTP_HEADER_DELIMITER);
        strcat(res, headers->hdrs[i]->value);
        strcat(res, HTTP_ENDL);
    }
    return res;
}

void http_free_headers(http_headers *headers)
{
    size_t i;
    if (headers->length) {
        for (i = 0; i < headers->length; ++i) {
            http_free_pair(headers->hdrs[i]);
        }
        free(headers->hdrs);
    }
}

http_string_pair *http_make_pair(const char* key, const char* value)
{
    http_string_pair *res = (http_string_pair *)malloc(sizeof(http_string_pair));
    res->key = (char*)malloc(strlen(key)+1);
    memcpy(res->key, key, strlen(key)+1);
    res->value = (char*)malloc(strlen(value)+1);
    memcpy(res->value, value, strlen(value)+1);
    return res;
}

void http_free_pair(http_string_pair *pair)
{
    if (pair) {
        if (pair->key)
            free(pair->key);
        if (pair->value)
            free(pair->value);
        free(pair);
    }
}


http_server.c
/* 
 * File:   tcpserver.cpp
 * Author: yurik
 *
 * Created on 24 Сентябрь 2008 г., 0:29
 */

#include "http.h"


#include <tcp_server.h>

#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>

#include <http.h>

#define PORT    5555
#define MAXMSG  512

/*
    char buffer[MAXMSG];
    int nbytes;

    nbytes = read(fd, buffer, MAXMSG);
    if (nbytes < 0) {
        // Read error.
        perror("read");
        return (EXIT_FAILURE);
    } else if (nbytes == 0) {
        // End-of-file.
        printf("Server: client exiting\n");
        return -1;
    } else {
        // Data read.
        printf("Server: got message: `%s'\n", buffer);
        return 0;
    }
*/

http_string_pair pairs[] = {
    { "Server", "Yurror's multithread http server" },
    { "Content-Type", "text/html; charset=UTF-8" },
    { "Connection", "close" },
    { NULL, NULL }
};

http_response *http_process_request(http_request *request)
{
    char ans[] = "<html><head><title>Hello</title></head><body><p>Hello, world!</p></body></html>";
    http_headers *headers = http_make_headers(pairs);
    http_response *res = http_make_response(200, headers, strlen(ans), ans);
    http_free_headers(headers);
    return res;
}

int http_client_handler(int fd)
{
    int res;
    http_buffer *buffer = http_make_buffer(fd);
    http_request *request = http_parse_request(buffer);
    http_free_buffer(buffer);
    
    http_response *response = http_process_request(request);
    http_free_request(request);
    
    buffer = http_assemble_response(response);
    http_free_response(response);
    
    res = http_buffer_send(buffer, fd);
    http_free_buffer(buffer);
    return res;
}

int main(int argc, char** argv)
{
    return tcp_server_start(PORT, http_client_handler);
}


tcp_server.c
#include <tcp_server.h>

#include <arpa/inet.h>
#include <netdb.h>

#include <pthread.h>

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

void *process_client(void *ptr)
{
    tcp_server_client *client = (tcp_server_client *)ptr;
/*
    printf ("Server: connect from host %s, port %d.\n",
        inet_ntoa(client->clientname.sin_addr),
            ntohs(client->clientname.sin_port)
    );
*/
    client->handler(client->fd);
    
    shutdown(client->fd, SHUT_RDWR);
    close(client->fd);
    free(client);
    pthread_exit(0);
}

int tcp_server_start(int port, tcp_server_handler handler)
{
    /* Create the socket and set it up to accept connections. */
    int sock;
    struct sockaddr_in name;

    /* Create the socket. */
    sock = socket(PF_INET, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("socket");
        return (EXIT_FAILURE);
    }

    /* Give the socket a name. */
    name.sin_family = AF_INET;
    name.sin_port = htons(port);
    name.sin_addr.s_addr = htonl(INADDR_ANY);
    if (bind(sock, (struct sockaddr *) & name, sizeof (name)) < 0) {
        perror("bind");
        return (EXIT_FAILURE);
    }

    if (listen(sock, 1) < 0) {
        perror("listen");
        return (EXIT_FAILURE);
    }

    while (1) {
        pthread_t thread;
        tcp_server_client *client =
                (tcp_server_client *)malloc(sizeof(tcp_server_client));

        client->size = sizeof (client->clientname);
        client->handler = handler;
        client->fd = accept(sock, (struct sockaddr *) &(client->clientname),
                &(client->size));

        if (client->fd < 0) {
            perror ("accept"); free(client); continue;
        }
        
        pthread_create(&thread, NULL, &process_client, (void *)client);
    }
}


http_buffer.h
/* 
 * File:   http_buffer.h
 * Author: yurik
 *
 * Created on 27 Сентябрь 2008 г., 0:21
 */

#ifndef _HTTP_BUFFER_H
#define    _HTTP_BUFFER_H

#ifdef    __cplusplus
extern "C" {
#endif
    
#include <sys/types.h>

typedef struct _http_buffer_block {
    size_t length;
    char *data;
    struct _http_buffer_block *next;
} http_buffer_block;

http_buffer_block *http_make_buffer_block(size_t length, const char *data);
http_buffer_block *http_free_buffer_block(http_buffer_block *block);
void http_free_buffer_blocks(http_buffer_block *block);

typedef struct {
    int fd;
    http_buffer_block *first;
    http_buffer_block *last;
} http_buffer;

#define HTTP_ENDL "\r\n"

http_buffer* http_make_buffer(int fd);
void http_free_buffer(http_buffer* buf);

size_t http_buffer_length(http_buffer* buf);
int http_buffer_recv(http_buffer* buf);

void http_buffer_append(http_buffer* buf, size_t length, const char* str);
char *http_buffer_readln(http_buffer* buf);
char *http_buffer_read(http_buffer* buf, size_t length);
int http_buffer_send(http_buffer *buf, int fd);

#ifdef    __cplusplus
}
#endif

#endif    /* _HTTP_BUFFER_H */


http.h
/* 
 * File:   http.h
 * Author: yurik
 *
 * Created on 26 Сентябрь 2008 г., 23:16
 */

#ifndef _HTTP_H
#define    _HTTP_H

#ifdef    __cplusplus
extern "C" {
#endif

#include <http_buffer.h>
    
typedef struct {
    char *key;
    char *value;
} http_string_pair;

typedef struct {
    size_t length;
    http_string_pair **hdrs;
} http_headers;

typedef struct {
    char *method;
    char *resource;
    http_headers *headers;
    size_t data_length;
    char *data;
} http_request;

typedef struct {
    int code;
    http_headers *headers;
    size_t data_length;
    char *data;
} http_response;

typedef struct {
    int code;
    char * str;
} http_code_table;

#define HTTP_HEADER_DELIMITER ": "

http_request* http_make_request(
        const char *method,
        const char *resource,
        const http_headers *headers,
        size_t data_length,
        const char *data
    );

void http_free_request(http_request* request);

http_request* http_parse_request(http_buffer* request);

http_response* http_make_response(
        int code,
        const http_headers *headers,
        size_t data_length,
        const char *data
    );

void http_free_response(http_response* response);

http_buffer *http_assemble_response(const http_response* response);

http_headers* http_make_headers(http_string_pair *pairs);
char *http_headers_to_text(http_headers *headers);
int http_headers_push_back(http_headers *headers, const http_string_pair *pair);
const char *http_headers_get_value(http_headers *headers, const char* key);
void http_free_headers(http_headers *headers);

http_string_pair* http_make_pair(const char* key, const char* value);
void http_free_pair(http_string_pair *pair);

#ifdef    __cplusplus
}
#endif

#endif    /* _HTTP_H */


tcp_server.h
/* 
 * File:   tcp_server.h
 * Author: yurik
 *
 * Created on September 27, 2008, 4:06 PM
 */

#ifndef _TCP_SERVER_H
#define    _TCP_SERVER_H

#ifdef    __cplusplus
extern "C" {
#endif

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

typedef int (*tcp_server_handler)(int);

typedef struct {
    int fd;
    tcp_server_handler handler;
    struct sockaddr_in clientname;
    socklen_t size;
} tcp_server_client;

int tcp_server_start(int port, tcp_server_handler handler);

#ifdef    __cplusplus
}
#endif

#endif    /* _TCP_SERVER_H */
Re[29]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.10.11 08:17
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Как ни прискорбно — но с boost у меня тоже не срослось.

это как?
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[30]: C++ listen tcp socket
От: Handler Украина  
Дата: 13.10.11 09:36
Оценка:
Взял первый же пример из boost.asio — date_time, который посылает клиенту ответ. Так вот, я не смог прочитать от клиента сообщение.
Однако, это не заставило меня отказаться от boost вообще — только сейчас мне важнее разобраться с сокетами и потоками:
Первым делом — самолеты, ну а девушки — потом...
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[31]: C++ listen tcp socket
От: niXman Ниоткуда https://github.com/niXman
Дата: 13.10.11 09:40
Оценка:
Здравствуйте, Handler, Вы писали:

H>не смог прочитать от клиента сообщение.

там ведь пара: клиент и сервер. примеры все рабочие. так что, этого не может быть.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[31]: C++ listen tcp socket
От: yurror Россия  
Дата: 13.10.11 10:19
Оценка:
Здравствуйте, Handler, Вы писали:

H>Взял первый же пример из boost.asio — date_time, который посылает клиенту ответ. Так вот, я не смог прочитать от клиента сообщение.

H>Однако, это не заставило меня отказаться от boost вообще — только сейчас мне важнее разобраться с сокетами и потоками:
H>Первым делом — самолеты, ну а девушки — потом...
Есть не только date_time. Есть примеры http-серверов.
Re[32]: C++ listen tcp socket
От: Handler Украина  
Дата: 17.10.11 11:02
Оценка:
Теперь встал еще один вопрос: Как отправить заголовок браузеру? Т.е.:
в php ч/з header(), а в с++ — ?
Начнем с самого простого, без чего, якобы, браузер вообще не сможет прочитать содержимое ответа (но, тем не менее, читает) — Content-length:
string str = "<html>...</html>";
string reply = "Content-length: "+str.length();
reply+= "\r\n\r\n"; // end of header
reply+= str;

Здесь все отлично — браузер отображает содержимое документа, причем сам заголовок в теле документа не отображается.
Далее хочу отправить кодировку в документ, т.к. документ у меня в cp-1251, а браузер — в utf-8 (default):
Какой же параметр устанавливает кодировку в заголовке?
google.com -> http header rfc -> http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
Читаю:
14.2 Accept-Charset
Accept-Charset: iso-8859-5, unicode-1-1;q=0.8
14.17 Content-Type
Content-Type: text/html; charset=ISO-8859-4
Пишу:
string str = "<html>...</html>";
string reply = "Accept-Charset: cp-1251"; //string reply = "Content-Type: text/html; charset=cp-1251"; 
reply+= "\r\n\r\n"; // end of header
reply+= str;

Ни один из этих вариантов браузер не считает за заголовки и выводит их в основное тело документа.
Как правильно и какие заголовки посылать браузеру?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[33]: C++ listen tcp socket
От: okman Беларусь https://searchinform.ru/
Дата: 17.10.11 14:23
Оценка: 2 (1)
Здравствуйте, Handler, Вы писали:

H>Теперь встал еще один вопрос: Как отправить заголовок браузеру? Т.е.:

H>в php ч/з header(), а в с++ — ?
H>Начнем с самого простого, без чего, якобы, браузер вообще не сможет прочитать содержимое ответа (но, тем не менее, читает) — Content-length:

Без Content-Length и браузер, и сервер, считают закрытие соединения признаком конца сообщения.
Хотя так делать крайне не рекомендуется.

H>
H>string str = "<html>...</html>";
H>string reply = "Content-length: "+str.length();
H>reply+= "\r\n\r\n"; // end of header
H>reply+= str;
H>

А где статусная строка (HTTP/1.1 200 OK) ?

H>Здесь все отлично — браузер отображает содержимое документа, причем сам заголовок в теле документа не отображается.

H>Далее хочу отправить кодировку в документ, т.к. документ у меня в cp-1251, а браузер — в utf-8 (default):
H>Какой же параметр устанавливает кодировку в заголовке?

Клиент говорит серверу о том, в какой кодировке он желает получить ответ, с помощью Accept-Charset.
Сервер обозначает кодировку ответа внутри Content-Type. Например: "Content-Type: text/html; charset=utf-8".
Если кодировка не указывается, для HTML по умолчанию берется ISO-8859-1, а для XHTML — UTF-8.

H>Ни один из этих вариантов браузер не считает за заголовки и выводит их в основное тело документа.

H>Как правильно и какие заголовки посылать браузеру?

Это потому, что Вы не читаете спецификацию, и, подозреваю, даже не заглядываете в предыдущие ответы темы.
А HTTP, между тем, не такой уж и примитивный протокол, и в нем не все лежит на поверхности.

Начинать нужно было не с форума, а отсюда:

Спецификации:
RFC 1945 (HTTP 0.9-1.0)
RFC 2616 (HTTP 1.1)

Книги:
HTTP Developer's Handbook (C. Shiflett)
HTTP: The Definitive Guide (D. Gourley, B. Totty, M. Sayer, S. Reddy, A. Aggarwal)
Web-протоколы: теория и практика НТТР/1.1, взаимодействие протоколов, кэширование, измерение трафика
(Б. Кришнамурти, Дж. Рексфорд)
Re[34]: C++ listen tcp socket
От: Handler Украина  
Дата: 18.10.11 06:54
Оценка:
O>А где статусная строка (HTTP/1.1 200 OK) ?

H>>
H>>string str = "<html><head><meta http-equiv="content-type" content="text/html; charset=windows-1251"></head>...</html>";
H>>string reply = "";
reply+= "HTTP/1.1 200 OK\r\n";
reply+= "Content-length: "+str.length();
H>>reply+= "\r\n\r\n"; // end of header
H>>reply+= str;
H>>


Все равно не видит кодировку.

O>Клиент говорит серверу о том, в какой кодировке он желает получить ответ, с помощью Accept-Charset.

O>Сервер обозначает кодировку ответа внутри Content-Type. Например: "Content-Type: text/html; charset=utf-8".
O>Если кодировка не указывается, для HTML по умолчанию берется ISO-8859-1, а для XHTML — UTF-8.

Вот что сервер получает от клиента:

GET / HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_4) AppleWebKit/535.1+ (KHTML, like Gecko) Version/5.0 Safari/533.16
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: uk-ua
Accept-Encoding: gzip, deflate
Connection: keep-alive

Сервер отдает документ с правильным содержимым Content-Type.

O>Начинать нужно было не с форума, а отсюда:


O>Спецификации:

O>RFC 1945 (HTTP 0.9-1.0)
O>RFC 2616 (HTTP 1.1)

O>Книги:

O>HTTP Developer's Handbook (C. Shiflett)
O>HTTP: The Definitive Guide (D. Gourley, B. Totty, M. Sayer, S. Reddy, A. Aggarwal)
O>Web-протоколы: теория и практика НТТР/1.1, взаимодействие протоколов, кэширование, измерение трафика
O>(Б. Кришнамурти, Дж. Рексфорд)

много текста — про способы передачи кодировки сервером клиенту, не известные мне ничего не написано
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[35]: C++ listen tcp socket
От: okman Беларусь https://searchinform.ru/
Дата: 18.10.11 07:13
Оценка:
Здравствуйте, Handler, Вы писали:

O>>А где статусная строка (HTTP/1.1 200 OK) ?


H>>>
H>>>string str = "<html><head><meta http-equiv="content-type" content="text/html; charset=windows-1251"></head>...</html>";
H>>>string reply = "";
H>reply+= "HTTP/1.1 200 OK\r\n";
H>reply+= "Content-length: "+str.length();
H>>>reply+= "\r\n\r\n"; // end of header
H>>>reply+= str;
H>>>


H>Все равно не видит кодировку.


Тут не хватает заголовка Content-Type c нужным charset-ом.

H>Вот что сервер получает от клиента:


H>GET / HTTP/1.1

H>Host: localhost:8080
H>User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_4) AppleWebKit/535.1+ (KHTML, like Gecko) Version/5.0 Safari/533.16
H>Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
H>Accept-Language: uk-ua
H>Accept-Encoding: gzip, deflate
H>Connection: keep-alive

А тут не хватает заголовка Accept-Charset.
Re[36]: C++ listen tcp socket
От: Handler Украина  
Дата: 18.10.11 11:30
Оценка:
Здравствуйте, okman, Вы писали:

H>>>>
H>>>>string str = "<html><head><meta http-equiv="content-type" content="text/html; charset=windows-1251"></head>...</html>";
H>>>>string reply = "";
H>>reply+= "HTTP/1.1 200 OK\r\n";
H>>reply+= "Content-length: "+str.length();
H>>>>reply+= "\r\n\r\n"; // end of header
H>>>>reply+= str;
H>>>>


O>Тут не хватает заголовка Content-Type c нужным charset-ом.


Вот я сейчас не понял — как и где его не хватает? В str он есть, а в заголовок его не надо писать.

H>>GET / HTTP/1.1

H>>Host: localhost:8080
H>>User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_4) AppleWebKit/535.1+ (KHTML, like Gecko) Version/5.0 Safari/533.16
H>>Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
H>>Accept-Language: uk-ua
H>>Accept-Encoding: gzip, deflate
H>>Connection: keep-alive

O>А тут не хватает заголовка Accept-Charset.


что мне клиент прислал, то я и показал- все вопросы к веб-браузеру. Да и как, собственно, браузер может требовать кодировку? Его дело — запрашивать документ и отображать его содержимое. Возможно, я не совсем понимаю Ваших намеков.
Проблемы с кодировкой наблюдались у меня в случае, когда я делал так:

wget google.com/index.html
И далее использовал полученный файл, как документ.
Если же я самостоятельно напишу документ в текстовом редакторе по всем правилам указания кодировок — таких проблем не возникает.

Теперь усложним задачу:
Для начала заметим, что значение дескриптора socket и accept в программе:
sock = socket(...);//4
session = accept(sock, ...); // 5

Теперь запустим нашу программу как демон из другой програмы:
if(!fork()) execl("myprog", argv);

Наша программа успешно запустилась и ждет входящих сообщений, но не обрабатывает их (т.е. по-просту, не работатет).
И почему-то указанные выше sock и session на 1 меньше:
sock = socket(...);//3
session = accept(sock, ...); // 4

Что тут не так?
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[37]: C++ listen tcp socket
От: okman Беларусь https://searchinform.ru/
Дата: 18.10.11 13:38
Оценка:
Здравствуйте, Handler, Вы писали:

O>>Тут не хватает заголовка Content-Type c нужным charset-ом.


H>Вот я сейчас не понял — как и где его не хватает? В str он есть, а в заголовок его не надо писать.


У веб-сервера, который отдает HTML-страницу, есть два места для указания кодировки.
Первое, и главное место, — это заголовок HTTP-ответа Content-Type.
В нем указывается MIME-тип документа и его кодировка.
Например: "Content-Type: text/html; charset=Windows-1251".

Второе место находится внутри самого HTML — это атрибуты элемента <meta>.
Но браузер не обязан на них смотреть. По спецификации HTTP (RFC 2616, Chapter 3.4.1),
если кодировка не указывается в заголовке Content-Type, по умолчанию принимается ISO-8859-1,
и наплевать что там внутри <meta>.

H>что мне клиент прислал, то я и показал- все вопросы к веб-браузеру. Да и как, собственно, браузер может требовать кодировку? Его дело — запрашивать документ и отображать его содержимое. Возможно, я не совсем понимаю Ваших намеков.


Браузер может запрашивать не только кодировку, но и язык, способ компрессии, метод передачи и другие данные.
Например, если Вы зайдете на Google из Китая, увидите главную страницу с иероглифами.
Вопрос — как это достигается ? Отнюдь не по айпи. Когда браузер шлет запрос серверу, в этом запросе
обычно указываются некоторые "пожелания":
Accept: text/html — хочу получить такую веб-страницу,
Accept-Language: ru — чтоб контент был на русском,
Accept-Charset: Windows-1251 — и чтоб все это было в кодировке Windows-1251,
Accept-Encoding: x-gzip — пусть сервер в целях экономии трафика пожмет страницу GZip-ом.

Если сервер в состоянии удовлетворить такие пожелания, он вернет нужный контент.
Если нет, будет ответ 400 (Bad Request), 406 (Not Accepted), или что-то в этом роде.

Само собой, браузер, установленный на компьютере с китайской локализацией операционной системы,
или настроенный на такую локализацию, будет слать запросы с другими Accept-ами и получать от
сервера данные в других языках и кодировках.

В приведенном коде эта техника игнорируется, поэтому результаты не совпадают с ожиданиями.

H>Проблемы с кодировкой наблюдались у меня в случае, когда я делал так:


H>wget google.com/index.html

H>И далее использовал полученный файл, как документ.
H>Если же я самостоятельно напишу документ в текстовом редакторе по всем правилам указания кодировок — таких проблем не возникает.

Я пока вижу только одну проблему — HTTP-запросы и ответы игнорируют заголовки Accept-Charset и Content-Type.

H>Теперь усложним задачу:

H>Для начала заметим, что значение дескриптора socket и accept в программе:
H>sock = socket(...);//4
H>session = accept(sock, ...); // 5

H>Теперь запустим нашу программу как демон из другой програмы:

H>if(!fork()) execl("myprog", argv);

H>Наша программа успешно запустилась и ждет входящих сообщений, но не обрабатывает их (т.е. по-просту, не работатет).

H>И почему-то указанные выше sock и session на 1 меньше:
H>sock = socket(...);//3
H>session = accept(sock, ...); // 4

H>Что тут не так?


Ну например, из-за того, что обе копии программы биндят сокет на один и тот же порт (8080).
Re: C++ listen tcp socket
От: okman Беларусь https://searchinform.ru/
Дата: 18.10.11 14:03
Оценка:
Здравствуйте, Handler.

Из самого первого сообщения темы:

H>Создать приложение демон-процесс, слушающий и обрабатывающий запросы к TCP порту основанные на HTTP, выдающий в результате обработки запроса HTML-контент взятый из базы данных mysql, выполняющий перекодирование выдаваемого контента в желаемую/затребованную кодировку, которая устанавливается либо в самом запросе, либо в настройках его инициализационных параметров.


Для перекодирования текстового содержимого нужно использовать сторонние библиотеки.
Например, iconv. Лично я предпочитаю библиотеку ICU.

Логика работы веб-сервера тогда будет примерно следующей:
Принимаем HTTP-запрос, вытаскиваем из заголовка "Accept-Charset" кодировку (или берем ее
из настроек нашего веб-сервера), затем добываем HTML-контент из базы данных, перегоняем
его в нужную кодировку, после чего формируем заголовки ответа, не забыв про Content-Type и
charset, и в полученном виде отдаем клиенту.
Re[2]: C++ listen tcp socket
От: Handler Украина  
Дата: 19.10.11 09:05
Оценка:
Из Ваших двух сообщений узнал больше, чем за все время разбора данной задачи — большое Вам спасибо.
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.