我需要在常规HttpHandler中获取客户端的IP地址,如下所示:
http = HttpHandler() do req::Request, res::Response
Response( ismatch(r"^/hello/",req.resource) ? string("Hello ", split(req.resource,'/')[3], "!") : 404 )
end
req
和http.sock
都不包含此信息。
答案 0 :(得分:5)
如果你稍微了解朱莉娅的内部结构,就可以做到这一点。事实证明,Julia使用库 libuv 进行低级系统处理,并且该库具有一个名为 uv_tcp_getpeername 的函数。 Julia.Base不会导出此函数,但您可以通过ccall访问它。此外,模块 HttpServer 允许为各种事件定义回调,包括 connect 事件。
module HTTPUtil
export get_server
using HttpServer
function handle_connect(client)
try
buffer = Array(Uint8,32)
bufflen::Int64 = 32
ccall(:uv_tcp_getpeername,Int64,(Ptr{Void},Ptr{Uint8},Ptr{Int64}),client.sock.handle,buffer,&bufflen)
peername::IPv4 = IPv4(buffer[5:8]...)
task_local_storage(:ip,peername)
catch e
println("Error ... $e")
end
end
function get_server()
http = HttpHandler() do req::Request, res::Response
ip = task_local_storage(:ip)
println("Connection received from from $ip")
Response(ismatch(r"^/hello/",req.resource)?string("Hello ",split(req.resource,'/')[3], " $(ip)!") : 404 )
end
http.events["connect"]=(client)->handle_connect(client)
server = Server(http)
end
end
每次发出连接请求时,服务器都会创建一个对等套接字,并调用 connect 处理程序,该处理程序被定义为 handle_connect 。它需要一个类型Client的客户端参数。 客户端 类型的字段名为 sock ,类型为TcpSocket, TcpSocket 有一个字段句柄,由 libuv 使用。然后,对象是每次发出连接请求时,都会调用连接处理程序,该处理程序使用 TcpSocket 中包含的数据调用 uv_tcp_getpeername 处理。声明一个字节数组充当缓冲区,然后将其转换回Base.IPv4。模块HTTPServer准确创建1 task for each client using @async,因此可以使用 task_local_storage 将IP地址存储在客户端本地;因此没有竞争条件。
julia> using HTTPUtil
julia> server = get_server()
Server(HttpHandler((anonymous function),TcpServer(init),Dict{ASCIIString,Function} with 3 entries:
"error" => (anonymous function)
"listen" => (anonymous function)
"connect" => (anonymous function)),nothing)
julia> @async run(server,8000)
Listening on 8000...
Task (queued) @0x000000000767e7a0
julia> Connection received from from 192.168.0.23
Connection received from from 192.168.0.22
... etc
答案 1 :(得分:1)
在waTeim的优秀answer的基础上,我简化了一些与IPv6兼容的事情,以及SSL连接:
using MbedTLS
function handle_connect(client)
ip, port = getsockname(isa(client.sock, MbedTLS.SSLContext) ? client.sock.bio : client.sock)
task_local_storage(:ip, ip)
end
答案 2 :(得分:0)
(本来是对Josh Bode的回答添加了这个评论,但我没有必要的声誉。)
请注意,自Julia v0.7起,有必要使用getpeername()
代替getsockname()
。
答案 3 :(得分:0)
感谢waTeim的回答,但是从2014年开始,朱莉娅的情况发生了变化。这在Julia 6.0中很有效,可能还有以上几点:
function ip(socket::TCPSocket)
buffer = Array{UInt8}(32)
bufflen::Int64 = 32
ccall(:uv_tcp_getpeername,Int64,(Ptr{Void},Ptr{UInt8},Ptr{Int64}), socket.handle, buffer, &bufflen)
peername::IPv4 = IPv4(buffer[5:8]...)
end
答案 4 :(得分:0)
根据您的情况,您可以传递linux命令。
userIP = strip(readstring(`hostname -i`), ['\n'])