还是关于PHP的二进制流问题
之前发了一帖: http://bbs.csdn.net/topics/391024843
版主给了回答,也能够解析出来,但却发现出来的结果与真实结果完全不一样,比如服务器返回给我的是: ip: 107.145.107.140, port: 26773
但我解析出来却变成了: ip: 46.48.46.48, port: 63271
这样就差的远了, 我用PHP去获取nodes信息,然后将nodes信息自己解析输出一遍,顺便把未解析数据发送给pthon解析一遍,然后两边对比,发现结果却不一样
PHP(使用了swoole):
<?php$serv = new swoole_server('0.0.0.0', 6882, SWOOLE_PROCESS, SWOOLE_SOCK_UDP);$serv->set(array( 'worker_num' => WORKER_NUM, 'daemonize' => false, 'max_request' => MAX_REQUEST, 'dispatch_mode' => 2, 'debug_mode' => 1));$serv->on('Start', function($serv){ echo "DHT Server start...\n"; $nid = get_node_id(); $msg = array( 't' => entropy(2), 'y' => 'q', 'q' => 'find_node', 'a' => array( 'id' => $nid, 'target' => $nid ) ); $serv->sendto(gethostbyname('router.bittorrent.com'), 6881, encode($msg));});$serv->on('Receive', function($serv, $fd, $from_id, $data){ echo "New receive from ip: "; $msg = decode($data); $fdinfo = $serv->connection_info($fd); echo $fdinfo['remote_ip'] . "\n"; if($msg['y'] == 'r'){ if(array_key_exists('nodes', $msg['r'])) //$this->response_actions($msg, array($fdinfo['remote_ip'], $fdinfo['remote_port'])); $nodes = decode_nodes($msg['r']['nodes']); foreach($nodes as $node){ echo "nid: " . $node->nid . ", ip: " . $node->ip . ", port: " . $node->port . "\n"; } $serv->sendto('127.0.0.1', 6813, $data); }});function entropy($length=20){ $s = ''; for($i=0;$i<$length;$i++) $s .= chr(mt_rand(0, 255)); return $s; }function get_node_id(){ return sha1(entropy()); }function get_neighbor($target, $nid){ return substr($target, 0, 10) . substr($nid, 0, -10); }function encode($msg){ return Bencode::encode($msg); }function decode($msg){ return Bencode::decode($msg); }function decode_nodes($msg){ $n = array(); $length = strlen($msg); // 由于每个node都为26位, 若总长度不等于26的倍数则直接返回 if(($length % 26) != 0) return $n; $i = 0; while($i<$length){ //$s = substr($msg, $i, 26); //$d = unpack('a20nid/Lip/Sport', $s); //var_dump($d); //$d = unpack('a20nid/lip/sport', $s); //var_dump($d); //$n[] = new Node($d['nid'], long2ip($d['ip']), $d['port']); $nid = substr($msg, $i, 20); var_dump($nid); $ip = substr($msg, $i+20, 4); var_dump($ip); $ip = long2ip(unpack('L', $ip)[1]); $port = substr($msg, $i+24, 2); var_dump($port); $port = unpack('s', $port)[1]; var_dump($port); //$n[] = new Node($nid, $ip, $port); $i += 26; } return $n; }$serv->start();
python:
#!/usr/bin/env python#encoding: utf-8import socketfrom hashlib import sha1from random import randintfrom struct import unpackfrom socket import inet_ntoafrom threading import Timer, Threadfrom time import sleepfrom collections import dequefrom bencode import bencode, bdecodedef decode_nodes(nodes): n = [] length = len(nodes) if(length % 26) != 0: return n for i in range(0, length, 26): nid = nodes[i:i+20] ip = inet_ntoa(nodes[i+20:i+24]) ip2 = nodes[i+20:i+24] print ip2 port = unpack("!H", nodes[i+24:i+26])[0] port2 = nodes[i+24:i+26] print port2 print "decode_nodes: nid: %s, ip: %s, port: %s\n" % (nid, ip, port)class DHTServer(): def __init__(self): self.ufd = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) self.ufd.bind(("0.0.0.0", 6813)) def process_find_node_response(self, msg, address): nodes = decode_nodes(msg["r"]["nodes"]) for node in nodes: (nid, ip, port) = node print "find_node: nid: %s, ip: %s, port: %s\n" % (nid, ip, port) def run(self): while True: try: (data, address) = self.ufd.recvfrom(65536) msg = bdecode(data) self.on_message(msg, address) except Exception: pass def on_message(self, msg, address): try: if msg["y"] == "r": if msg["r"].has_key("nodes"): self.process_find_node_response(msg, address) except KeyError: passif __name__ == "__main__": # max_node_qsize bigger, bandwith bigger, spped higher dht = DHTServer() dht.run()
回复讨论(解决方案)
你把执行 decode_nodes($msg) 时的 $msg 用
echo base64_encode($msg);
输出出来看看
这个不是base64编码,而是类似于:
未编码: {"t":"aa", "y":"r", "r":{"id":"0123456789abcdefghij", "nodes":"def456..."}}
编码后:d1:rd2:id20:0123456789abcdefghij5:nodes9:def456...e1:t2:aa1:y1:re
这样的格式
而其中的nodeid、ip、port就是其中的nodes里的
你把执行 decode_nodes($msg) 时的 $msg 用
echo base64_encode($msg);
输出出来看看
这里有份DHT协议说明: http://blog.csdn.net/xxxxxx91116/article/details/7970815
我又不做这个,没兴趣看协议文本
我给你的解码格式是小端序的,如果你的数据是大端序的,那么就查一下 pack 函数说明,换一下
如果你想让我帮你检查,那么就请按我说的去做
4楼版主说的对,检查大小端序的问题。
或者用tcpdump实际的二进制数据是什么样的。
现在已经能够正确获取IP地址,但是端口依然无解,也的确是使用大端序,但PHP只有这几种格式,每个都试过,就是不正确,郁闷了。。。
那有什么办法呢?让你贴出数据你又不肯,只能这样了
啊,没有不肯啊,是这样的:
比如服务器发了一段数据过来,ip是:188.19.238.146,端口是:6881,然后我截取端口位的2字节数据为:?
接着就是解码,将网络字节序转换为端口号:unpack("n", $port),但是转换出来却变成了57763,用unpack("s", $port)变成了-23583,用unpack("S", $port)变成了41953
让你把你收到的数据用 base64_encode 编码后给我,怎么就那么难呢?
让你把你收到的数据用 base64_encode 编码后给我,怎么就那么难呢?
抱歉,是这样的数据:
ZDE6cmQyOmlkMjA6daCpq0ZCdc6JP5An4ac4g4tlvPg1Om5vZGVzNDE2Oj4jyz4WVIOIxzAe2MXW4TWcH8dddZ6SRDktJ+7silGRA0YlQqlqucmPix2E6MZCvQ2ZY90lCzORZu5ZytoyWpBtKzh4PVNLMrz+Vo4exiqGYEUq3sV501VNWQ5XcqsXfXftr47cYrvZHsF4DCDFWnMcgC2Aq/DHVz00Wbxfm9qPqlsdaJ4um4dXnVtZ6BLCGgy42Pw3zVOnROrqVgpFb1J5g+BAxB2NOUMBBW7FQCyycNBojCpaDATl59Ekq4HpaHqD1gW057xisIRLgEp9f9VZvdr60s6C3CBNCX/OvoTfeJyY40k3SdswZ1lTimGVQRb7T7/VTO1rgXkZFTpuvAYbPCJaWUpbXcILoZh8A8H/qzKyirIM0v8lycJgFFdeiZR7bq+aPmxHVL1Scc6M3YMH17kiA8lK3l06cqN65EvX3/CuWJ4uw+fDhqSjVCkrwlpdQYO8k8mjkZhdVAaHCBUDxw9ESlvAXxuYGuFHYq2GV1BOhSYgmPJSaOzkghl0kq9lCiQvWUhr/ewsm/X/90CEXsTS45jet3HqWuZ2KcjVZTE6dDI6e8cxOnkxOnJl
python 中有
n = [] length = len(nodes) if(length % 26) != 0: return n
模 26 为 6
请确认你给的数据是正确的
python 中有
n = [] length = len(nodes) if(length % 26) != 0: return n
模 26 为 6
请确认你给的数据是正确的
哦,抱歉,是这样的,刚才给出的是获取到的原始数据,而之后那里 % 26那个是通过bencode解码后的nodes数据,不好意思,忘了把这份数据也弄出来。。。
这份是原始数据,包含了获取到的所有,比如:y = r 之类的
ZDE6cmQyOmlkMjA6O+Bji1UaqD0DtxQvYyoA6qxsWGQ1Om5vZGVzNDE2Oj/SyPVGoEWNKA31UnEp7simR5o0TuvCi3ZXP9LI9UagRY0oDfVScSnuyKZHmjRO68KLdlc/0sj1RqBFjSgN9VJxKe7IpkeaNE7rwot2Vz/8I+41PITGHXJVPESiGTTO7b2UsbfqyB+QP/wj7jU8hMYdclU8RKIZNM7tvZSxt+rIH5A//CPuNTyExh1yVTxEohk0zu29lLG36sgfkD//TOin7ijhPGnlvhNEku1IO1B2ZcxGPhrhP/9M6KfuKOE8aeW+E0SS7Ug7UHZlzEY+GuE//0zop+4o4Txp5b4TRJLtSDtQdmXMRj4a4T5OjQM7NuWY8RSq0Ca2RI235AIYPBmGgBrhPk6NAzs25ZjxFKrQJrZEjbfkAhg8GYaAGuE+To0DOzblmPEUqtAmtkSNt+QCGDwZhoAa4T7PZbZs/9SbpdgANMEQ8dHeHtgBUeAsw9vgPs9ltmz/1Jul2AA0wRDx0d4e2AFR4CzD2+A+z2W2bP/Um6XYADTBEPHR3h7YAVHgLMPb4D2owBNmJWRvv7qjzQoEM7j+lo0O36b9DRrhZTE6dDg6LZGYmOd7p/sxOnkxOnJl
这份是通过bencode解码后的nodes数据,也就是在这个数据中分成每份26字节,从26字节中取出20字节的nid,4字节的ip,2字节的端口:
P9LI9UagRY0oDfVScSnuyKZHmjRO68KLdlc/0sj1RqBFjSgN9VJxKe7IpkeaNE7rwot2Vz/SyPVGoEWNKA31UnEp7simR5o0TuvCi3ZXP/wj7jU8hMYdclU8RKIZNM7tvZSxt+rIH5A//CPuNTyExh1yVTxEohk0zu29lLG36sgfkD/8I+41PITGHXJVPESiGTTO7b2UsbfqyB+QP/9M6KfuKOE8aeW+E0SS7Ug7UHZlzEY+GuE//0zop+4o4Txp5b4TRJLtSDtQdmXMRj4a4T//TOin7ijhPGnlvhNEku1IO1B2ZcxGPhrhPk6NAzs25ZjxFKrQJrZEjbfkAhg8GYaAGuE+To0DOzblmPEUqtAmtkSNt+QCGDwZhoAa4T5OjQM7NuWY8RSq0Ca2RI235AIYPBmGgBrhPs9ltmz/1Jul2AA0wRDx0d4e2AFR4CzD2+A+z2W2bP/Um6XYADTBEPHR3h7YAVHgLMPb4D7PZbZs/9SbpdgANMEQ8dHeHtgBUeAsw9vgPajAE2YlZG+/uqPNCgQzuP6WjQ7fpv0NGuE=
$s = 'P9LI9UagRY0oDfVScSnuyKZHmjRO68KLdlc/0sj1RqBFjSgN9VJxKe7IpkeaNE7rwot2Vz/SyPVGoEWNKA31UnEp7simR5o0TuvCi3ZXP/wj7jU8hMYdclU8RKIZNM7tvZSxt+rIH5A//CPuNTyExh1yVTxEohk0zu29lLG36sgfkD/8I+41PITGHXJVPESiGTTO7b2UsbfqyB+QP/9M6KfuKOE8aeW+E0SS7Ug7UHZlzEY+GuE//0zop+4o4Txp5b4TRJLtSDtQdmXMRj4a4T//TOin7ijhPGnlvhNEku1IO1B2ZcxGPhrhPk6NAzs25ZjxFKrQJrZEjbfkAhg8GYaAGuE+To0DOzblmPEUqtAmtkSNt+QCGDwZhoAa4T5OjQM7NuWY8RSq0Ca2RI235AIYPBmGgBrhPs9ltmz/1Jul2AA0wRDx0d4e2AFR4CzD2+A+z2W2bP/Um6XYADTBEPHR3h7YAVHgLMPb4D7PZbZs/9SbpdgANMEQ8dHeHtgBUeAsw9vgPajAE2YlZG+/uqPNCgQzuP6WjQ7fpv0NGuE=';$s = base64_decode($s);foreach(str_split($s, 26) as $s) { $r = unpack('a20n/Nip/np', $s); $r['ip'] = long2ip($r['ip']); print_r($r);}
Array( [n] => ?ÒÈõF E?(õRq)îȦG?4 [ip] => 78.235.194.139 [p] => 30295)Array( [n] => ?ÒÈõF E?(õRq)îȦG?4 [ip] => 78.235.194.139 [p] => 30295)Array( [n] => ?ÒÈõF E?(õRq)îȦG?4 [ip] => 78.235.194.139 [p] => 30295)Array( [n] => ?ü#î5<?ÆrU<D¢4Îí½” [ip] => 177.183.234.200 [p] => 8080)Array( [n] => ?ü#î5<?ÆrU<D¢4Îí½” [ip] => 177.183.234.200 [p] => 8080)Array( [n] => ?ü#î5<?ÆrU<D¢4Îí½” [ip] => 177.183.234.200 [p] => 8080)Array( [n] => ?ÿLè§î(á<iå¾D’íH;Pv [ip] => 101.204.70.62 [p] => 6881)Array( [n] => ?ÿLè§î(á<iå¾D’íH;Pv [ip] => 101.204.70.62 [p] => 6881)Array( [n] => ?ÿLè§î(á<iå¾D’íH;Pv [ip] => 101.204.70.62 [p] => 6881)Array( [n] => >N?;6å?ñª?&¶D?·ä [ip] => 60.25.134.128 [p] => 6881)Array( [n] => >N?;6å?ñª?&¶D?·ä [ip] => 60.25.134.128 [p] => 6881)Array( [n] => >N?;6å?ñª?&¶D?·ä [ip] => 60.25.134.128 [p] => 6881)Array( [n] => >Ïe¶lÿÔ?¥Ø4ÁñÑ?Ø [ip] => 81.224.44.195 [p] => 56288)Array( [n] => >Ïe¶lÿÔ?¥Ø4ÁñÑ?Ø [ip] => 81.224.44.195 [p] => 56288)Array( [n] => >Ïe¶lÿÔ?¥Ø4ÁñÑ?Ø [ip] => 81.224.44.195 [p] => 56288)Array( [n] => =¨Àf%do¿º£Í3¸??? [ip] => 223.166.253.13 [p] => 6881)
$s = 'P9LI9UagRY0oDfVScSnuyKZHmjRO68KLdlc/0sj1RqBFjSgN9VJxKe7IpkeaNE7rwot2Vz/SyPVGoEWNKA31UnEp7simR5o0TuvCi3ZXP/wj7jU8hMYdclU8RKIZNM7tvZSxt+rIH5A//CPuNTyExh1yVTxEohk0zu29lLG36sgfkD/8I+41PITGHXJVPESiGTTO7b2UsbfqyB+QP/9M6KfuKOE8aeW+E0SS7Ug7UHZlzEY+GuE//0zop+4o4Txp5b4TRJLtSDtQdmXMRj4a4T//TOin7ijhPGnlvhNEku1IO1B2ZcxGPhrhPk6NAzs25ZjxFKrQJrZEjbfkAhg8GYaAGuE+To0DOzblmPEUqtAmtkSNt+QCGDwZhoAa4T5OjQM7NuWY8RSq0Ca2RI235AIYPBmGgBrhPs9ltmz/1Jul2AA0wRDx0d4e2AFR4CzD2+A+z2W2bP/Um6XYADTBEPHR3h7YAVHgLMPb4D7PZbZs/9SbpdgANMEQ8dHeHtgBUeAsw9vgPajAE2YlZG+/uqPNCgQzuP6WjQ7fpv0NGuE=';$s = base64_decode($s);foreach(str_split($s, 26) as $s) { $r = unpack('a20n/Nip/np', $s); $r['ip'] = long2ip($r['ip']); print_r($r);}
Array( [n] => ?ÒÈõF E?(õRq)îȦG?4 [ip] => 78.235.194.139 [p] => 30295)Array( [n] => ?ÒÈõF E?(õRq)îȦG?4 [ip] => 78.235.194.139 [p] => 30295)Array( [n] => ?ÒÈõF E?(õRq)îȦG?4 [ip] => 78.235.194.139 [p] => 30295)Array( [n] => ?ü#î5<?ÆrU<D¢4Îí½” [ip] => 177.183.234.200 [p] => 8080)Array( [n] => ?ü#î5<?ÆrU<D¢4Îí½” [ip] => 177.183.234.200 [p] => 8080)Array( [n] => ?ü#î5<?ÆrU<D¢4Îí½” [ip] => 177.183.234.200 [p] => 8080)Array( [n] => ?ÿLè§î(á<iå¾D’íH;Pv [ip] => 101.204.70.62 [p] => 6881)Array( [n] => ?ÿLè§î(á<iå¾D’íH;Pv [ip] => 101.204.70.62 [p] => 6881)Array( [n] => ?ÿLè§î(á<iå¾D’íH;Pv [ip] => 101.204.70.62 [p] => 6881)Array( [n] => >N?;6å?ñª?&¶D?·ä [ip] => 60.25.134.128 [p] => 6881)Array( [n] => >N?;6å?ñª?&¶D?·ä [ip] => 60.25.134.128 [p] => 6881)Array( [n] => >N?;6å?ñª?&¶D?·ä [ip] => 60.25.134.128 [p] => 6881)Array( [n] => >Ïe¶lÿÔ?¥Ø4ÁñÑ?Ø [ip] => 81.224.44.195 [p] => 56288)Array( [n] => >Ïe¶lÿÔ?¥Ø4ÁñÑ?Ø [ip] => 81.224.44.195 [p] => 56288)Array( [n] => >Ïe¶lÿÔ?¥Ø4ÁñÑ?Ø [ip] => 81.224.44.195 [p] => 56288)Array( [n] => =¨Àf%do¿º£Í3¸??? [ip] => 223.166.253.13 [p] => 6881)
非常非常感谢,看来是我一开始截取的时候就截取错了,所以获取到的结果才会不对,真的太感谢了!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Alipay PHP ...

세션 납치는 다음 단계를 통해 달성 할 수 있습니다. 1. 세션 ID를 얻으십시오. 2. 세션 ID 사용, 3. 세션을 활성 상태로 유지하십시오. PHP에서 세션 납치를 방지하는 방법에는 다음이 포함됩니다. 1. 세션 _regenerate_id () 함수를 사용하여 세션 ID를 재생산합니다. 2. 데이터베이스를 통해 세션 데이터를 저장하십시오.

JWT는 주로 신분증 인증 및 정보 교환을 위해 당사자간에 정보를 안전하게 전송하는 데 사용되는 JSON을 기반으로 한 개방형 표준입니다. 1. JWT는 헤더, 페이로드 및 서명의 세 부분으로 구성됩니다. 2. JWT의 작업 원칙에는 세 가지 단계가 포함됩니다. JWT 생성, JWT 확인 및 Parsing Payload. 3. PHP에서 인증에 JWT를 사용하면 JWT를 생성하고 확인할 수 있으며 사용자 역할 및 권한 정보가 고급 사용에 포함될 수 있습니다. 4. 일반적인 오류에는 서명 검증 실패, 토큰 만료 및 대형 페이로드가 포함됩니다. 디버깅 기술에는 디버깅 도구 및 로깅 사용이 포함됩니다. 5. 성능 최적화 및 모범 사례에는 적절한 시그니처 알고리즘 사용, 타당성 기간 설정 합리적,

PHP 개발에서 견고한 원칙의 적용에는 다음이 포함됩니다. 1. 단일 책임 원칙 (SRP) : 각 클래스는 하나의 기능 만 담당합니다. 2. Open and Close Principle (OCP) : 변경은 수정보다는 확장을 통해 달성됩니다. 3. Lisch의 대체 원칙 (LSP) : 서브 클래스는 프로그램 정확도에 영향을 미치지 않고 기본 클래스를 대체 할 수 있습니다. 4. 인터페이스 격리 원리 (ISP) : 의존성 및 사용되지 않은 방법을 피하기 위해 세밀한 인터페이스를 사용하십시오. 5. 의존성 반전 원리 (DIP) : 높고 낮은 수준의 모듈은 추상화에 의존하며 종속성 주입을 통해 구현됩니다.

시스템이 다시 시작된 후 UnixSocket의 권한을 자동으로 설정하는 방법. 시스템이 다시 시작될 때마다 UnixSocket의 권한을 수정하려면 다음 명령을 실행해야합니다.

phpstorm에서 CLI 모드를 디버그하는 방법은 무엇입니까? PHPStorm으로 개발할 때 때때로 CLI (Command Line Interface) 모드에서 PHP를 디버그해야합니다 ...

정적 바인딩 (정적 : :)는 PHP에서 늦은 정적 바인딩 (LSB)을 구현하여 클래스를 정의하는 대신 정적 컨텍스트에서 호출 클래스를 참조 할 수 있습니다. 1) 구문 분석 프로세스는 런타임에 수행됩니다. 2) 상속 관계에서 통화 클래스를 찾아보십시오. 3) 성능 오버 헤드를 가져올 수 있습니다.

PHP 개발에서 PHP의 CURL 라이브러리를 사용하여 JSON 데이터를 보내면 종종 외부 API와 상호 작용해야합니다. 일반적인 방법 중 하나는 컬 라이브러리를 사용하여 게시물을 보내는 것입니다 ...
