设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 1499|回复: 9

[通用发布] 异步可并发HTTP通信库(更新:可获取下载进度、取消操作)

[复制链接]

TA还没有解放自身的潜力。

Lv3.寻梦者

梦石
0
星屑
1508
在线时间
126 小时
注册时间
2013-10-6
帖子
188
发表于 2015-2-23 23:13:36 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有帐号?注册会员

x
本帖最后由 不死鸟之翼 于 2015-5-17 12:39 编辑

当前版本:Version 0.2 (26KB)
https://azurefx.name/article/win ... %bf%a1%e5%ba%93dll/

这个动态链接库是为方便RGSS中进行常见HTTP通信而设计的,支持多连接并发。一共导出了6个函数。
CPP 代码复制打印下载
  1. DWORD WINAPI Create(LPCSTR server,LPCSTR action,LPCSTR method,LPCSTR data);
  2. DWORD WINAPI CreateEx(LPCSTR server,LPCSTR action,LPCSTR method,LPCSTR data,LPCSTR ctype,LPCSTR ua);
  3. INT WINAPI Query(DWORD token);
  4. INT WINAPI QueryEx(DWORD token,LPDWORD bytesTotal,LPDWORD bytesLoaded);
  5. INT WINAPI Retrieve(DWORD token,LPVOID buffer);
  6. 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)

点评

不知道是不是我的使用方式不对,不过CreateEx貌似不太行==  发表于 2015-3-18 01:16

评分

参与人数 1星屑 +140 收起 理由
喵呜喵5 + 140 精品文章

查看全部评分

TA还没有解放自身的潜力。

Lv3.寻梦者

梦石
0
星屑
1508
在线时间
126 小时
注册时间
2013-10-6
帖子
188
 楼主| 发表于 2015-2-23 23:19:53 | 显示全部楼层
本帖最后由 不死鸟之翼 于 2015-2-25 15:50 编辑

【注意】0.2版本的status状态有变动,使用0.1版本配套脚本的同学请留意下载中的状态为PROGRESS而不是PENDING
如果是多连接并发,请保管好token。
我亲测开10个连接同时下载WinRAR的安装程序,没问题
然后 @kuerlulu 求食用姿势
←你看到一只经常潜水的萌新。
回复 支持 反对

使用道具 举报

[动态]还没有进行过任何战斗 (打开TA的战斗卡片)

Lv1.梦旅人

梦石
0
星屑
80
在线时间
749 小时
注册时间
2011-7-17
帖子
782
发表于 2015-2-23 23:45:21 | 显示全部楼层
赞一个
回复 支持 反对

使用道具 举报

TA还没有解放自身的潜力。

Lv1.梦旅人

梦石
0
星屑
167
在线时间
434 小时
注册时间
2009-1-1
帖子
643
发表于 2015-2-24 08:12:49 | 显示全部楼层
点赞!很迅速嘛~初步测试了下正常获取网页信息
用这个来实时收发消息或许能够制作网游呢。。。
最近在研究XAS
回复 支持 反对

使用道具 举报

TA还没有解放自身的潜力。

Lv3.寻梦者

梦石
0
星屑
1508
在线时间
126 小时
注册时间
2013-10-6
帖子
188
 楼主| 发表于 2015-2-24 10:55:09 | 显示全部楼层
赛露休斯 发表于 2015-2-24 08:12
点赞!很迅速嘛~初步测试了下正常获取网页信息
用这个来实时收发消息或许能够制作网游呢。。。 ...

网游的话还是应该直接使用TCP长连接比较好。这个更适合一次性提交数据,例如制作网络排行榜功能。
←你看到一只经常潜水的萌新。
回复 支持 反对

使用道具 举报

TA还没有解放自身的潜力。

Lv1.梦旅人

梦石
0
星屑
70
在线时间
1378 小时
注册时间
2012-7-5
帖子
1702

开拓者

发表于 2015-2-24 15:04:26 | 显示全部楼层
发一个我刚写的Http#用之前先把上一个exe版本的Http删掉【本人的水平拙劣,代码风格奇特,恐不符大众口味,还望见谅。
RUBY 代码复制打印下载
  1. class Http
  2.   Create   = Win32API.new('AHttp.dll', 'Create',   'pppp', 'l')
  3.   Query    = Win32API.new('AHttp.dll', 'Query',    'l',    'i')
  4.   Retrieve = Win32API.new('AHttp.dll', 'Retrieve', 'lp',   'i')
  5.   Close    = Win32API.new('AHttp.dll', 'Close',    'l',    'l')
  6.   INVALID = 0;    SUCCESS = 1;    FAILURE = 2;    PENDING = 3
  7.   def initialize(server, action, method, data="")
  8.     @token = Create.call(server, action, method, data)
  9.   end
  10.   def query
  11.     Query.call(@token)
  12.   end
  13.   def retrieve
  14.     if query == SUCCESS
  15.       length = Retrieve.call(@token, 0)
  16.       buffer = "\0" * length
  17.       Retrieve.call(@token, buffer)
  18.       return buffer
  19.     end # or nil
  20.   end
  21.   def close
  22.     Close.call(@token)
  23.   end
  24. end

食用姿势:
第一步 下载主L跳转页里的AHttp_xx.dll并重命名为AHttp.dll放进游戏根目录
第二步 仅供参考【最后一步人工close将由 @taroxd 优化为自动close(finalizer) 等楼下出现天使触请一起愉快食用
【更多代码参考参考请见 https://rpg.blue/thread-376836-1-1.html
  1. def hy_rgss_run(*objs)
  2.   loop do
  3.     Graphics.update
  4.     Input.update
  5.     objs.each(&:update)
  6.     yield(*objs) if block_given?
  7.   end
  8. end

  9. h = Http.new("www.baidu.com", "s?wd=Hello,World!", "GET")
  10. hy_rgss_run do
  11.   case h.query
  12.   when Http::SUCCESS
  13.     # 对接收来的数据(h.retrieve)的操作
  14.     # 比如 print h.retrieve
  15.   when Http::FAILURE
  16.     # 获取失败时的操作
  17.   when Http::PENDING
  18.     # "载入中"时的操作
  19.   end
  20.   break if Input.trigger?('esc')
  21. end
  22. h.close
复制代码
【Input 模块被重写了, 所以直接复制的童鞋们Input.trigger?('esc')这一行会报错
【我这也是提醒你们不要随便用 以及手动close真的很容易忽视掉

点评

喵3好棒  发表于 2015-2-24 15:47
嗯 还有个Symbol#to_proc, xp的童鞋请在前面加一行class Symbol; def to_proc; lambda{|rec, *a| rec.send(self, *a)}; end; end  发表于 2015-2-24 15:12

  -fk: -azogi:
回复 支持 反对

使用道具 举报

TA还没有解放自身的潜力。

Lv3.寻梦者

梦石
0
星屑
1508
在线时间
126 小时
注册时间
2013-10-6
帖子
188
 楼主| 发表于 2015-2-24 15:39:12 手机端发表。 | 显示全部楼层
kuerlulu 发表于 2015-2-24 15:04
发一个我刚写的Http#用之前先把上一个exe版本的Http删掉【本人的水平拙劣,代码风格奇特,恐不符大众口味, ...

你直接Win32 API的话至少三个HINTERNET句柄,都要手动Close掉……总之资源释放是好习惯,推荐扔到析构函数里一劳永逸。实际上FreeLibrary的时候DllMain里面会进行一次大清理,操作系统还会清理一边,所以也就是在运行期间泄露一点内存而已)雾,取决于你下载了多大的文件
回复 支持 反对

使用道具 举报

TA还没有解放自身的潜力。

Lv1.梦旅人

梦石
0
星屑
70
在线时间
1378 小时
注册时间
2012-7-5
帖子
1702

开拓者

发表于 2015-2-24 17:01:39 | 显示全部楼层
本帖最后由 kuerlulu 于 2015-2-24 17:36 编辑

还有一个下载器【噗
下载器

然后就有了 0.png 放在你游戏根目录= =   

  -fk: -azogi:
回复 支持 反对

使用道具 举报

TA还没有解放自身的潜力。

Lv3.寻梦者

梦石
0
星屑
1508
在线时间
126 小时
注册时间
2013-10-6
帖子
188
 楼主| 发表于 2015-2-25 15:53:07 | 显示全部楼层
更新后可以获取下载进度了,也可以中断操作
@kuerlulu 你的下载器可以有进度条了:)
←你看到一只经常潜水的萌新。
回复 支持 反对

使用道具 举报

TA还没有解放自身的潜力。

Lv1.梦旅人

路人党员

梦石
0
星屑
51
在线时间
2276 小时
注册时间
2010-12-30
帖子
3226
发表于 2015-3-17 22:55:06 | 显示全部楼层
kuerlulu 发表于 2015-2-24 15:04
发一个我刚写的Http#用之前先把上一个exe版本的Http删掉【本人的水平拙劣,代码风格奇特,恐不符大众口味, ...

帮你改进了一些==
  1. class HTTP
  2.   Create   = Win32API.new('AHttp.dll', 'Create',   'pppp',   'l')
  3.   CreateEx = Win32API.new('AHttp.dll', 'CreateEx', 'pppppp', 'l')
  4.   Query    = Win32API.new('AHttp.dll', 'QueryEx',  'lpp',    'i')
  5.   Retrieve  = Win32API.new('AHttp.dll', 'Retrieve', 'lp',     'i')
  6.   Close    = Win32API.new('AHttp.dll', 'Close',    'l',      'l')
  7.   INVALID  = 0;    SUCCESS = 1;    FAILURE = 2;    PENDING = 3
  8.   def initialize(type, server, action, meth, data, ctype = "", browser = "")
  9.     @token = type == 0 ?
  10.               Create.call(server, action, meth, data) :
  11.               CreateEx.call(server, action, meth, ctype, browser)
  12.     @total = [0].pack("L")
  13.     @loaded = [0].pack("L")
  14.   end
  15.   def total_bytes
  16.     query
  17.     return @total.unpack("L").first
  18.   end
  19.   def loaded_bytes
  20.     query
  21.     return @loaded.unpack("L").first
  22.   end
  23.   def query
  24.     Query.call(@token, @total, @loaded)
  25.   end
  26.   def retrieve
  27.     if query == SUCCESS
  28.       length = Retrieve.call(@token, 0)
  29.       buffer = "\0" * length
  30.       Retrieve.call(@token, buffer)
  31.       return buffer
  32.     end
  33.   end
  34.   def close
  35.     Close.call(@token)
  36.   end
  37.   def self.create(server, action, meth, data={})
  38.     @conn = new(0, server, action, meth, data_encode(data))
  39.     if block_given?
  40.       yield @conn
  41.       @conn.close
  42.     else
  43.       return @conn
  44.     end
  45.   end
  46.   def self.create_ex(server, action, meth, ctype, browser, data={})
  47.     @conn = new(0, server, action, meth, data_encode(data), ctype, browser)
  48.     if block_given?
  49.       yield @conn
  50.       @conn.close
  51.     else
  52.       return @conn
  53.     end
  54.   end
  55.   def self.data_encode(data)
  56.     d = ""
  57.     data.each_pair do |k, v|
  58.       d += "%" + k.to_s.unpack("C*").map{|s|s.to_s(16)}.join("%") + "="
  59.       d += "%" + v.to_s.unpack("C*").map{|s|s.to_s(16)}.join("%") + "&"
  60.     end
  61.     return d.sub(/.$/, "")
  62.   end
  63.   private_class_method :new, :data_encode
  64. end
复制代码

  1. s = Sprite.new
  2. b = Bitmap.new(640, 32)
  3. s.bitmap = b
  4. #HTTP.create("localhost", "projects/test.php", "POST", {"test"=>"hahahaha"}){ |h|
  5. HTTP.create("rpg.blue", "forum.php", "GET"){ |h|
  6.         while(!h.retrieve)
  7.     b.clear
  8.     b.draw_text(0,0, 640, 32, "#{h.query}:#{h.loaded_bytes}/#{h.total_bytes}")
  9.     Graphics.update
  10.         end
  11.   b.clear
  12.   b.draw_text(0,0, 640, 32, "#{h.query}:#{h.loaded_bytes}/#{h.total_bytes}")
  13.   Graphics.update
  14.         print(h.retrieve)
  15. }
  16. exit
复制代码

评分

参与人数 1星屑 +30 收起 理由
kuerlulu + 30 棒棒哒

查看全部评分

本人擅长XP,如果有脚本或者Ruby方面的问题欢迎发电邮到engshun@1ppl.me咨询,本人很少检查电邮所以不一定会及时回复,本人不会直接出手解决问题只会提供一个方向,所以谢绝伸手党
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:fux2@moe9th.com|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2019-7-22 14:11

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表