我正在尝试在OCaml中编写一个http客户端:
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没有返回像C这样的int响应,所以我假设我连接或创建了一个错误的连接或创建了运行时会引发错误的套接字。
如果您不熟悉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);
如果没用,请忽略它。我想我会用伪代码总结一下。有什么明显的问题吗? (除了不读取C中socket / connect / write的int响应,因为OCaml的运行时应该?在这里处理错误。)
答案 0 :(得分:2)
在HTTP
协议中,请求最终应该有两个空行,而不是一行(用外行术语表示)。在您的情况下,服务器只是等待第二个&#34;输入&#34;,并且您的客户端阻塞,直到它收到响应。只需在您的请求中添加额外的\r\n
,一切都会有效......更好。至少你会收到回复。但是你的代码包含一些故障,所以期望出现问题。
仅为了您的信息,在OCaml中有很多很好的网络库。我认为最好的是cohttp
。此外,您可能会发现有趣的我的socket library,比cohttp