Получить запрос через время ожидания соединения сокета во время чтения

Я пытаюсь написать http-клиент в OCaml:

module Connection = struct
    let sock_fd =
        let s_fd = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0 in
        Unix.setsockopt s_fd Unix.TCP_NODELAY true;
        s_fd

    let read_from_sock () =
        let buffer = Bytes.create 512 in
        let rec read_all request buffer =
            let r = Unix.read sock_fd buffer 0 512 in
            if r < 512 then request ^ buffer
            else read_all (request ^ buffer) buffer in
        read_all "" buffer

    let write_to_sock str =
        let len = String.length str in
        let _ = Unix.write sock_fd str 0 len in ()

    let make_request request serv_addr =
        Unix.connect sock_fd serv_addr;
        write_to_sock request

    class connection address port =
        object
            val serv_addr = Unix.ADDR_INET (Unix.inet_addr_of_string address, port)

            method get_response request =
                let _ = make_request request serv_addr in
                let rec wait_for_response () =
                    let response = read_from_sock () in
                    match String.length response with
                    | 0 -> wait_for_response ()
                    | _ -> Printf.printf "%s\n" response in
                wait_for_response ();
                Unix.shutdown sock_fd Unix.SHUTDOWN_ALL;
                Unix.close sock_fd
        end

    let create address port = new connection address port
end

let connection = Connection.create "54.175.219.8" 80;;
connection#get_response "GET / HTTP/1.1\r\n"

Программа просто зависает до тех пор, пока не вылетит при сбросе соединения во время чтения. Самое интересное, что никаких других ошибок не выдается. Поскольку OCaml не возвращает ответ типа int, как C, я бы предположил, что если я сделал что-то неправильное при подключении или создании сокета, среда выполнения выдаст ошибку.

Если вы не знакомы с OCaml, я бы предположил (чрезвычайно грубый) псевдо-C эквивалент того, что я делаю (возможно, это поможет при отладке):

int sock_fd = socket(PF_INET, SOCK_STREAM);
setsockopt(sock_fd, TCP_NODELAY, 1);

serv_addr addr {"54.175.219.8", 80};
connect(sock_fd, &serv_addr);
write(sock_fd, "GET / HTTP/1.1\r\n");

char buffer[512];
while (buffer = read(sock_fd)) {
    printf("%s\n", buffer);
}

shutdown(sock_fd, SHUTDOWN_ALL);
close(sock_fd);

Если это не помогает, игнорируйте это. Я просто решил обобщить в псевдокоде. Есть ли явные проблемы? (Помимо того, что не читается ответ int от socket/connect/write в C, потому что среда выполнения OCaml должна? позаботиться о выдаче здесь ошибок.)


person eatonphil    schedule 23.02.2015    source источник
comment
что вы имеете в виду под сбоями?   -  person ivg    schedule 23.02.2015
comment
Я получаю ошибку времени выполнения (соединение сбрасывается во время чтения, как я уже говорил), которая, если ее не поймать, приводит к выходу программы.   -  person eatonphil    schedule 23.02.2015
comment
это не ошибка времени выполнения, это исключение, говорящее о том, что соединение было сброшено удаленным узлом.   -  person ivg    schedule 23.02.2015


Ответы (1)


В протоколе HTTP запрос должен заканчиваться двумя пустыми строками, а не одной (в терминах непрофессионала). В вашем случае сервер просто ждет второго «входа», а ваш клиент блокируется, пока не получит ответ. Просто добавьте дополнительные \r\n к вашему запросу, и все будет работать... лучше. По крайней мере, вы получите ответ. Но ваш код содержит некоторые сбои, так что ожидайте, что что-то пойдет не так.

К вашему сведению, в OCaml есть много хороших библиотек для работы в сети. Лучшим, на мой взгляд, является cohttp. Кроме того, вы можете найти интересную мою библиотеку сокетов, которая немного более низкоуровневая, чем cohttp

person ivg    schedule 23.02.2015
comment
Хороший звонок! И вы правы, это было исключением, а не ошибкой. Моя вина там. Спасибо и за советы по библиотеке, мне просто нравится бездельничать ради образования. - person eatonphil; 23.02.2015
comment
тогда я бы также посоветовал прочитать эту прекрасную книгу. Он очень низкоуровневый, но похоже, что вас это не напугает - person ivg; 23.02.2015