tfsn20 发表于 2022-12-1 23:15:32

发送16进制数据请求和接收

本帖最后由 tfsn20 于 2022-12-2 10:56 编辑

> 本帖最后由 tfsn20 于 2022-12-2 10:55 编辑

> 本帖最后由 tfsn20 于 2022-12-1 23:24 编辑

感谢冷山哥哥提供的帮助和关键代码。🙂
demo地址(https://scriptcat.org/script-show-page/747),
打开[微信官网](https://weixin.qq.com/)使用。
发送一个16进制数据的post请求
```
let data = '19f10400a10000009d0104f10100a8025673537bdac747ed5a33862dc0b17c1b669ae7cdb1d99e341dcc9c4d89aae46386d0ac0000006f010000006a000f01000000630100093a80000000000048000c7fc14e6523d35471e93f64fd004814d6def5ffb908b002c7c0ee8ccc182e161ee06ccf701db0f74a20ac18a141651341830b9849dd653e85d79940c5036748b2cb8e0b85cb4997e628e0a100d1018d73af281b69e79c19f10400249804a8cdabe5d1842dd7bcaa4ed8ad0ac132eac2ed7a771bfa3ccbc404f456fd0c446cd417f1040195bb17859e5a4b3bc7a86c154159cc7c2804f681f03a5f3437b3d9d500bc1cef57b2ad7c4aef8a9c160632a5e1b9de76ffcbc8b393d719bd2e6418f65ff257684ab7ada6c02ac3d63074d2508bc7002e44417577a0ede9d4765ef9938b9eff95e1a5356bea737c20db98f612d392563cee95d3d6cc6a43d3942ca4d1d5cd5ec12a4e48ce905ba334ac28e8732024f37d6bbe623a9247323ca15889d9b9435ab21702ba54a246955870ed2f5b4e7b63d73badee8d74daf86926559fa1b4c82721305f389b8c60d38ae0f9d553002b04230590c2818add7deeed131a625f054677a6c55d8518c5dc15099add0341bcb8b25550e30ae4495df7fd22949586c5ccf8e6e56a66d608a0259010de0cbcfd76dc416a33778533eda25b856c0f7ef476d4285c60ab5a31a4ce6b6afacee5c520fadd32247fd17189731fa7c54fba4844bd2e62d5038085f99bb78fe915a4558cb64ea259dbbb3c2b15c4dacf2773d8abd59d4b893bd54b59965faaa4f944b224abd4ffbb54d43d19b534672488cc52de9a8420dee99628f90ea45a815d8e96e6ff7925f986c40e15f1040017e6e3ae6c8a48c97704dbfde7bd0dbc186af534e1bbc654';
```
直接转为数字不行,一是太大,而是大数要求必须是整数;
先创建一个具有data.length/2字节的Uint8Array
```
let buffer = new Uint8Array(data.length/2)
```
再两个两个的转为10进制放入buffer内
```
for (let i = 0, len = data.length; i < len; i = i + 2) {
      buffer=(parseInt(data + data, 16))
    }
```
parseInt()函数可以把data+data这个字符串以16进制读取,返回10进制的数,所以放入buffer内的是10进制的数,parseInt的第一个参数还可以是数字
```
parseInt(10,2)
```
返回2,因为10以2进制读取就是10进制的2,然后请求的data需要把buffer转为blob读取`data: new Blob(),`具体如下

```
GM_xmlhttpRequest({
                url: 'http://szextshort.weixin.qq.com/mmtls/3755b7e7',
                method: 'POST',
                data: new Blob(),
                anonymous: anonymous,
                responseType: 'blob',
                headers: {
                  'sec-ch-ua-platform': '',
                  'dnt': '',
                  'sec-ch-ua': '',
                  'sec-ch-ua-mobile': '',
                  'Sec-Fetch-Site': '',
                  'Sec-Fetch-Mode': '',
                  'Sec-Fetch-Dest': '',
                  'User-Agent': 'MicroMessenger Client',
                  'Accept-Encoding': '',
                  'Content-Type': 'application/octet-stream',
                  'Accept': '*/*',
                  'Accept-Language': '',
                  //'Content-Length': '',
                  'Cache-Control': 'no-cache',
                  'Host': 'szextshort.weixin.qq.com',
                  'Upgrade': 'mmtls',
                  'Referer': '',
                  'origin': '',
                  'Cookie': ''
                  },
                  onload:function(xhr){resolve()}
                }
```
buffer的内存数据刚好就是我们要传输的数据
!(data/attachment/forum/202212/01/220222o5q5m765539kncl3.png)!(data/attachment/forum/202212/01/220213nzve8xkiozdkkzk5.png),最后是接收数据,设置`responseType: 'blob',`,因为我们要接收一个流,
```
                  let blob = xhr.response;
                  var fr = new FileReader();
                  fr.readAsArrayBuffer(blob);
```
将blob以文件形式读取到fr中,在内存查看器就可以发现我们想要的数据了
!(data/attachment/forum/202212/01/221040qo9c3of8lz94frq9.png)
!(data/attachment/forum/202212/01/221117btpg7ef7esg3sa77.png)
将onload里的代码改改就可以输出16进制字符串了
```
let blob = xhr.response;
var fr = new FileReader();
unsafeWindow.fr = fr;
fr.addEventListener("load", function (ev) {
    var abb = ev.target.result;
    var iAA = new Uint8Array(abb);
    // console.log(iAA);
    // console.info(fr);
    console.log(unsafeWindow.iAA = iAA);
    let t = '';
    for (let i = 0, len = iAA.length; i < len; i++) {
      t = t + iAA.toString(16);
    }
    console.log(t)
});
//把blob文件转化为arraybuffer;
fr.readAsArrayBuffer(blob);
```

!(data/attachment/forum/202212/01/221408jzzj4zwen8yine0e.png)
为什么用Uint8array,Uint8Array代表8个比特,也就是一个字节,代表他每个内存单元存储一个字节,我们要发送的数据是645个字节,刚好645个坑,如果用Unit16Array,就是2个字节一个坑,这导致645个字节前644个占了322个坑,最后一个字节一个坑占不完,会填充0,导致数据不对。而且不知道为啥每两个字节都颠倒了顺序,如图
!(data/attachment/forum/202212/01/225313h5vsiz2jiks5ci7w.png)
!(data/attachment/forum/202212/01/225317qx37o7nkrf7nrmk4.png)
代码如下:
```
let data = '19f10400a10000009d0104f10100a8025673537bdac747ed5a33862dc0b17c1b669ae7cdb1d99e341dcc9c4d89aae46386d0ac0000006f010000006a000f01000000630100093a80000000000048000c7fc14e6523d35471e93f64fd004814d6def5ffb908b002c7c0ee8ccc182e161ee06ccf701db0f74a20ac18a141651341830b9849dd653e85d79940c5036748b2cb8e0b85cb4997e628e0a100d1018d73af281b69e79c19f10400249804a8cdabe5d1842dd7bcaa4ed8ad0ac132eac2ed7a771bfa3ccbc404f456fd0c446cd417f1040195bb17859e5a4b3bc7a86c154159cc7c2804f681f03a5f3437b3d9d500bc1cef57b2ad7c4aef8a9c160632a5e1b9de76ffcbc8b393d719bd2e6418f65ff257684ab7ada6c02ac3d63074d2508bc7002e44417577a0ede9d4765ef9938b9eff95e1a5356bea737c20db98f612d392563cee95d3d6cc6a43d3942ca4d1d5cd5ec12a4e48ce905ba334ac28e8732024f37d6bbe623a9247323ca15889d9b9435ab21702ba54a246955870ed2f5b4e7b63d73badee8d74daf86926559fa1b4c82721305f389b8c60d38ae0f9d553002b04230590c2818add7deeed131a625f054677a6c55d8518c5dc15099add0341bcb8b25550e30ae4495df7fd22949586c5ccf8e6e56a66d608a0259010de0cbcfd76dc416a33778533eda25b856c0f7ef476d4285c60ab5a31a4ce6b6afacee5c520fadd32247fd17189731fa7c54fba4844bd2e62d5038085f99bb78fe915a4558cb64ea259dbbb3c2b15c4dacf2773d8abd59d4b893bd54b59965faaa4f944b224abd4ffbb54d43d19b534672488cc52de9a8420dee99628f90ea45a815d8e96e6ff7925f986c40e15f1040017e6e3ae6c8a48c97704dbfde7bd0dbc186af534e1bbc654';
    let bytesArray = []
    for (let i = 0, len = data.length; i < len; i = i + 4) {
      bytesArray.push(parseInt(data + data+data+data, 16));
    }
    let buffer = new Uint16Array(bytesArray)
```
这样写不用设置TypeArray的大小了,很方便,事实上这个buffer是646字节。
关于为什么用UintArray16储存时每两个字节会颠倒顺序可以参考这几篇文章
[搞懂 ArrayBuffer、TypedArray、DataView 的对比和使用](https://juejin.cn/post/7005810137491308580)
[详解-定型数组-DataView-ArrayBuffer](https://juejin.cn/post/7100231821815709709#comment)
[什么是大端小端 and 如何判断大端小端](https://blog.csdn.net/weixin_43202635/article/details/115430316)
!(data/attachment/forum/202212/02/102758ss694p6p6pcpsmwt.png)
原因是操作系统存储数据时的大小端模式,总结是用TypedArray构造的buffer不能设置大小端,且根据操作系统来定,即一个16进制19f1存储成小端就是f119,用DataView构造的buffer可以设置大小端,且默认是大端。TCP/IP协议规定传输的数据必须是大端。
[为什么存在 大端 模式 小端](https://zhuanlan.zhihu.com/p/360037797)
[为什么会有大小端模式之分呢?](https://blog.csdn.net/loveprogram_1/article/details/30464761)
比如一个16进制19f1,19是高字节,f1是低字节,放到内存0x0010中,如果是小端模式,将f1放到低内存位,即0x0010,将19放到高内存位,即0x0010往后移一个字节,即0x0011,大端相反。
小端模式优点:
内存的低地址处存放低字节,所以在强制转换数据时不需要调整字节的内容(注解:比如把int的4字节强制转换成short的2字节时,就直接把int数据存储的前两个字节给short就行,因为其前两个字节刚好就是最低的两个字节,符合转换逻辑);
CPU做数值运算时从内存中依顺序依次从低位到高位取数据进行运算,直到最后刷新最高位的符号位,这样的运算方式会更高效。
大端模式优点:
符号位在所表示的数据的内存的第一个字节中,便于快速判断数据的正负和大小。
其各自的优点就是对方的缺点,正因为两者彼此不分伯仲,再加上一些硬件厂商的坚持,因此在多字节存储顺序上始终没有一个统一的标准。
16进制每两位就是1字节,0b11111111==0xff,这样得来。
再次感谢冷山哥哥🙂。(首尾呼应了)

hysaoh 发表于 2022-12-2 02:39:17

哥哥nb,不用客气!!!

wwwwwllllk 发表于 2022-12-2 08:53:26

gg这是传输什么了,为什么要这样做了

李恒道 发表于 2022-12-2 09:38:42

这个太猛了...牛逼!

脚本体验师001 发表于 2022-12-2 11:36:28

火贴留名

tfsn20 发表于 2022-12-2 12:51:10

wwwwwllllk 发表于 2022-12-2 08:53
gg这是传输什么了,为什么要这样做了

算是发送字节流数据,作为post的请求数据

806350554 发表于 2023-10-10 13:47:52

看不懂看不懂
页: [1]
查看完整版本: 发送16进制数据请求和接收