Project1
标题: 异步可并发HTTP通信库(更新:可获取下载进度、取消操作) [打印本页]
作者: 不死鸟之翼 时间: 2015-2-23 23:13
标题: 异步可并发HTTP通信库(更新:可获取下载进度、取消操作)
本帖最后由 不死鸟之翼 于 2015-5-17 12:39 编辑
当前版本:Version 0.2 (26KB)
https://azurefx.name/article/win ... %bf%a1%e5%ba%93dll/
这个动态链接库是为方便RGSS中进行常见HTTP通信而设计的,支持多连接并发。一共导出了6个函数。
DWORD WINAPI Create(LPCSTR server,LPCSTR action,LPCSTR method,LPCSTR data);
DWORD WINAPI CreateEx(LPCSTR server,LPCSTR action,LPCSTR method,LPCSTR data,LPCSTR ctype,LPCSTR ua);
INT WINAPI Query(DWORD token);
INT WINAPI QueryEx(DWORD token,LPDWORD bytesTotal,LPDWORD bytesLoaded);
INT WINAPI Retrieve(DWORD token,LPVOID buffer);
BOOL WINAPI Close(DWORD token);
DWORD WINAPI Create(LPCSTR server,LPCSTR action,LPCSTR method,LPCSTR data);
DWORD WINAPI CreateEx(LPCSTR server,LPCSTR action,LPCSTR method,LPCSTR data,LPCSTR ctype,LPCSTR ua);
INT WINAPI Query(DWORD token);
INT WINAPI QueryEx(DWORD token,LPDWORD bytesTotal,LPDWORD bytesLoaded);
INT WINAPI Retrieve(DWORD token,LPVOID buffer);
BOOL WINAPI Close(DWORD token);
Create
开始一个HTTP请求。server为主机名,action为请求的资源,method为请求类型,data为附加数据。
函数会返回一个token代表这个请求,请保存以便后续使用。
例如Create(“www.baidu.com”,”s?wd=Hello,World!”,”GET”,””);
更多示例请参见另一篇文章
CreateEx
其他参数同Create。ctype为HTTP请求头中的Content-type,ua为浏览器标识。
Query
查询指定请求的状态。返回值可能如下:
INVALID=0
SUCCESS=1
FAILURE=2
PENDING=3
PROGRESS=4
INVALID代表无效的token,SUCCESS代表成功,FAILURE代表失败,PENDING代表请求等待回应,PROGRESS表示正在下载数据。
QueryEx
其他参数同Query。bytesTotal和bytesLoaded分别为接收总大小和已下载大小的变量指针。若无法获取总大小,bytesTotal的值为0xFFFFFFFF。
Retrieve
获取返回的数据。buffer为接收数据的缓冲区。
仅当请求状态为SUCCESS时调用这个函数。如果buffer为0则返回缓冲区所需的长度。
返回值为已接收的数据长度。
Close
关闭一个请求,释放资源。一个请求完成时务必调用这个函数。
返回值为零表示失败,非零表示成功。
所有函数均为__stdcall调用约定。
类型注释:
DWORD 32位无符号整数(l)
INT 32位整数(i)
BOOL 32位整数(i)
LPCSTR C风格字符串的指针(p)
LPDWORD 32位无符号整数的指针(p)
LPVOID 缓冲区指针(p)
作者: 不死鸟之翼 时间: 2015-2-23 23:19
本帖最后由 不死鸟之翼 于 2015-2-25 15:50 编辑
【注意】0.2版本的status状态有变动,使用0.1版本配套脚本的同学请留意下载中的状态为PROGRESS而不是PENDING
如果是多连接并发,请保管好token。
我亲测开10个连接同时下载WinRAR的安装程序,没问题
然后 @kuerlulu 求食用姿势
作者: 火星·奈 时间: 2015-2-23 23:45
赞一个
作者: 赛露休斯 时间: 2015-2-24 08:12
点赞!很迅速嘛~初步测试了下正常获取网页信息
用这个来实时收发消息或许能够制作网游呢。。。
作者: 不死鸟之翼 时间: 2015-2-24 10:55
赛露休斯 发表于 2015-2-24 08:12 
点赞!很迅速嘛~初步测试了下正常获取网页信息
用这个来实时收发消息或许能够制作网游呢。。。 ...
网游的话还是应该直接使用TCP长连接比较好。这个更适合一次性提交数据,例如制作网络排行榜功能。
作者: kuerlulu 时间: 2015-2-24 15:04
发一个我刚写的Http#用之前先把上一个exe版本的Http删掉【本人的水平拙劣,代码风格奇特,恐不符大众口味,还望见谅。
class Http
Create = Win32API.new('AHttp.dll', 'Create', 'pppp', 'l')
Query = Win32API.new('AHttp.dll', 'Query', 'l', 'i')
Retrieve = Win32API.new('AHttp.dll', 'Retrieve', 'lp', 'i')
Close = Win32API.new('AHttp.dll', 'Close', 'l', 'l')
INVALID = 0; SUCCESS = 1; FAILURE = 2; PENDING = 3
def initialize(server, action, method, data="")
@token = Create.call(server, action, method, data)
end
def query
Query.call(@token)
end
def retrieve
if query == SUCCESS
length = Retrieve.call(@token, 0)
buffer = "\0" * length
Retrieve.call(@token, buffer)
return buffer
end # or nil
end
def close
Close.call(@token)
end
end
class Http
Create = Win32API.new('AHttp.dll', 'Create', 'pppp', 'l')
Query = Win32API.new('AHttp.dll', 'Query', 'l', 'i')
Retrieve = Win32API.new('AHttp.dll', 'Retrieve', 'lp', 'i')
Close = Win32API.new('AHttp.dll', 'Close', 'l', 'l')
INVALID = 0; SUCCESS = 1; FAILURE = 2; PENDING = 3
def initialize(server, action, method, data="")
@token = Create.call(server, action, method, data)
end
def query
Query.call(@token)
end
def retrieve
if query == SUCCESS
length = Retrieve.call(@token, 0)
buffer = "\0" * length
Retrieve.call(@token, buffer)
return buffer
end # or nil
end
def close
Close.call(@token)
end
end
食用姿势:
第一步 下载主L跳转页里的AHttp_xx.dll并重命名为AHttp.dll放进游戏根目录
第二步 仅供参考【最后一步人工close将由 @taroxd 优化为自动close(finalizer) 等楼下出现天使触请一起愉快食用
【更多代码参考参考请见 https://rpg.blue/thread-376836-1-1.html- def hy_rgss_run(*objs)
- loop do
- Graphics.update
- Input.update
- objs.each(&:update)
- yield(*objs) if block_given?
- end
- end
- h = Http.new("www.baidu.com", "s?wd=Hello,World!", "GET")
- hy_rgss_run do
- case h.query
- when Http::SUCCESS
- # 对接收来的数据(h.retrieve)的操作
- # 比如 print h.retrieve
- when Http::FAILURE
- # 获取失败时的操作
- when Http::PENDING
- # "载入中"时的操作
- end
- break if Input.trigger?('esc')
- end
- h.close
复制代码 【Input 模块被重写了, 所以直接复制的童鞋们Input.trigger?('esc')这一行会报错
【我这也是提醒你们不要随便用 以及手动close真的很容易忽视掉
作者: 不死鸟之翼 时间: 2015-2-24 15:39
kuerlulu 发表于 2015-2-24 15:04
发一个我刚写的Http#用之前先把上一个exe版本的Http删掉【本人的水平拙劣,代码风格奇特,恐不符大众口味, ...
你直接Win32 API的话至少三个HINTERNET句柄,都要手动Close掉……总之资源释放是好习惯,推荐扔到析构函数里一劳永逸。实际上FreeLibrary的时候DllMain里面会进行一次大清理,操作系统还会清理一边,所以也就是在运行期间泄露一点内存而已)雾,取决于你下载了多大的文件
作者: kuerlulu 时间: 2015-2-24 17:01
本帖最后由 kuerlulu 于 2015-2-24 17:36 编辑
还有一个下载器【噗
下载器
然后就有了
放在你游戏根目录= =
作者: 不死鸟之翼 时间: 2015-2-25 15:53
更新后可以获取下载进度了,也可以中断操作
@kuerlulu 你的下载器可以有进度条了:)
作者: 英顺的马甲 时间: 2015-3-17 22:55
kuerlulu 发表于 2015-2-24 15:04 
发一个我刚写的Http#用之前先把上一个exe版本的Http删掉【本人的水平拙劣,代码风格奇特,恐不符大众口味, ...
帮你改进了一些==- class HTTP
- Create = Win32API.new('AHttp.dll', 'Create', 'pppp', 'l')
- CreateEx = Win32API.new('AHttp.dll', 'CreateEx', 'pppppp', 'l')
- Query = Win32API.new('AHttp.dll', 'QueryEx', 'lpp', 'i')
- Retrieve = Win32API.new('AHttp.dll', 'Retrieve', 'lp', 'i')
- Close = Win32API.new('AHttp.dll', 'Close', 'l', 'l')
- INVALID = 0; SUCCESS = 1; FAILURE = 2; PENDING = 3
- def initialize(type, server, action, meth, data, ctype = "", browser = "")
- @token = type == 0 ?
- Create.call(server, action, meth, data) :
- CreateEx.call(server, action, meth, ctype, browser)
- @total = [0].pack("L")
- @loaded = [0].pack("L")
- end
- def total_bytes
- query
- return @total.unpack("L").first
- end
- def loaded_bytes
- query
- return @loaded.unpack("L").first
- end
- def query
- Query.call(@token, @total, @loaded)
- end
- def retrieve
- if query == SUCCESS
- length = Retrieve.call(@token, 0)
- buffer = "\0" * length
- Retrieve.call(@token, buffer)
- return buffer
- end
- end
- def close
- Close.call(@token)
- end
- def self.create(server, action, meth, data={})
- @conn = new(0, server, action, meth, data_encode(data))
- if block_given?
- yield @conn
- @conn.close
- else
- return @conn
- end
- end
- def self.create_ex(server, action, meth, ctype, browser, data={})
- @conn = new(0, server, action, meth, data_encode(data), ctype, browser)
- if block_given?
- yield @conn
- @conn.close
- else
- return @conn
- end
- end
- def self.data_encode(data)
- d = ""
- data.each_pair do |k, v|
- d += "%" + k.to_s.unpack("C*").map{|s|s.to_s(16)}.join("%") + "="
- d += "%" + v.to_s.unpack("C*").map{|s|s.to_s(16)}.join("%") + "&"
- end
- return d.sub(/.$/, "")
- end
- private_class_method :new, :data_encode
- end
复制代码
- s = Sprite.new
- b = Bitmap.new(640, 32)
- s.bitmap = b
- #HTTP.create("localhost", "projects/test.php", "POST", {"test"=>"hahahaha"}){ |h|
- HTTP.create("rpg.blue", "forum.php", "GET"){ |h|
- while(!h.retrieve)
- b.clear
- b.draw_text(0,0, 640, 32, "#{h.query}:#{h.loaded_bytes}/#{h.total_bytes}")
- Graphics.update
- end
- b.clear
- b.draw_text(0,0, 640, 32, "#{h.query}:#{h.loaded_bytes}/#{h.total_bytes}")
- Graphics.update
- print(h.retrieve)
- }
- exit
复制代码
欢迎光临 Project1 (https://rpg.blue/) |
Powered by Discuz! X3.1 |