【发布时间】:2015-01-18 19:16:37
【问题描述】:
我在从 Python 套接字服务器读取数据时遇到问题。我已经尝试了几种方法,并且几个月来一直在寻找解决方案。
我试图从 Python 套接字服务器获得的响应每次都不同。第一次可以是 40 个字符,下一次可以超过 10k 个字符。
我尝试使用 socket_recv() 和 fgets() 到目前为止 fgets 最适合我的需要,因为socket_recv 没有得到 fgets 的全部响应。只有一个问题。与 socket_recv 相比,它要慢得多,而且并不总是能得到响应。
fgets 遇到的问题是,无论大小,本地连接都需要 2.02 秒才能获得响应。
我需要它来解决问题,但我一生都无法弄清楚如何解决它..
连接到 Python 套接字服务器只需要 22ms,所以我不明白为什么要花很长时间才能获得整个响应。
哦,如果有帮助,响应是 JSON 字符串。
这是我使用的代码:
/*
* Recieve
*/
public function recv() {
if (!$this->connected()) {
$this->_errorStr = 'Recieve timeout';
$this->_error = true;
return false;
}
$buf = '';
while ($line = fgets($this->_socket)) {
$buf .= $line;
}
return json_decode($buf);
}
如果你需要全班:
class Sockets {
/*
* Variables
*/
private $_id,
$_name,
$_ip,
$_port,
$_socket,
$_socketTimeout = 1,
$_triedConnect = false,
$_errorStr = '',
$_error = false;
/*
* Construct class
*/
public function __construct($ip, $port) {
$this->_ip = $ip;
$this->_port = $port;
$this->_socket = false;
}
/*
* Send command
*/
public function command($cmd, $json = true) {
if ($json) {
$cmd = json_encode($cmd);
}
if (!$this->send($cmd)) {
return $this->_errorStr;
}
$r = $this->recv();
if (!$r) {
return $this->_errorStr;
}
return $r;
}
/*
* Connect to server
*/
public function connect() {
$this->_error = false;
if ($this->_triedConnect) {
$this->_errorStr = 'Failed to connect.';
$this->_error = true;
return false;
}
$this->_triedConnect = true;
$this->_errorStr = '';
$errno = 0;
$errstr = '';
$this->_socket = @pfsockopen($this->_ip, $this->_port, $errno, $errstr, $this->_socketTimeout);
if (!$this->_socket) {
$this->_errorStr = sprintf('Can\'t connect to server.. (%errno: %errstr)', $errno, $errstr);
$this->_error = true;
$this->_socket = false;
return false;
}
stream_set_timeout($this->_socket, $this->_socketTimeout);
// Clear stream
while ($this->dataReady()) {
if (!fgets($this->_socket)) {
break;
}
}
if (!$this->connected()) {
$this->_errorStr = 'Lost connection to server!';
$this->_error = true;
$this->_socket = false;
return $this->_errorStr;
}
return true;
}
/*
* Authentication
*/
public function auth() {
}
/*
* Connected
*/
public function connected() {
return $this->_socket !== false;
}
/*
* Data ready
*/
public function dataReady() {
if (!$this->connected()) {
return false;
}
return @stream_select($r = array($this->_socket), $w = null, $x = null, 0) > 0;
}
/*
* Send data
*/
public function send($data) {
if (!$this->connected()) {
$this->_errorStr = 'Not connected!';
$this->_error = true;
return false;
}
if (@fwrite($this->_socket, $data) === false) {
$this->_errorStr = 'Failed to send command!';
$this->_error = true;
return false;
}
return true;
}
/*
* Recieve
*/
public function recv() {
if (!$this->connected()) {
$this->_errorStr = 'Recieve timeout';
$this->_error = true;
return false;
}
$buf = '';
while ($line = fgets($this->_socket)) {
$buf .= $line;
}
return json_decode($buf);
}
/*
* Disconnect
*/
public function disconnect() {
if (!$this->connected()) {
return;
}
fclose($this->_socket);
$this->_socket = false;
$this->_triedConnect = false;
}
}
非常感谢任何帮助!
编辑
我使用的机器运行的是 Windows 8.1 Pro,带有 Media Center。
我正在为安装了以下依赖项的服务器使用 Python 2.7.9:
psutil <- https://pypi.python.org/pypi/psutil
colorama <- https://pypi.python.org/pypi/colorama
pycrypto <- http://www.voidspace.org.uk/python/modules.shtml#pycrypto
什么类型的 TCP 套接字服务器根本无关紧要。只是一个基本的应该只是为了测试这个。即使没有依赖关系。像this 这样的东西可以工作。
对于 PHP,我使用 Wamp 和 PHP 5.5.12 并启用了以下模块:
php_bz2
php_com_dotnet
php_curl
php_exif
php_fileinfo
php_gd2
php_gettext
php_gmp
php_imap
php_intl
php_ldap
php_mbstring
php_mysql
php_mysqli
php_openssl
php_pdo_mysql
php_pdo_sqlite
php_shmop
php_soap
php_sockets
php_sqlite3
php_xmlrpc
php_xsl
默认情况下启用部分(如果不是全部)。
要测试 Sockets 类,您只需要这样:
// Import class file
require_once 'Sockets.php';
$socket = new Sockets('127.0.0.1', 21); // Change the port accordingly
// Connect to socket server
$socket->connect();
// Now in my case, the socket server responds to JSON strings, and nothing else.
// So I am going to show you show I send a command.
$command = array(
'key' => 'encrypted key', // This key is to do some validation on the server-side
'command' => 'command' // This is the command to be issued.
);
// Send command to socket server and dump the response
var_dump($socket->command($command));
// To send a plainstring command use this instead
var_dump($socket->command('command here', false));
【问题讨论】:
-
您的测试环境由什么组成。即你连接到什么服务器?您是否尝试过使用各种可用 Python 教程中的一些“示例”代码?请使用回复更新您的问题,而不是发布 cmets。 tcp/ip 的东西通常非常可靠。 2 秒的延迟可能是某种超时问题。这只是一个猜测。
-
问题已更新@RyanVincent
-
你误解了我的要求。首先,如果我决定“试一试”你的“问题”。你需要知道我在 Windows XP 电脑上运行它,使用我安装的任何版本的“python”(2.7.8)和 PHP 5.3.18。现在,如果您的代码工作正常 - 这对您有帮助吗?我怀疑不是。您需要详细指定您的 python 版本、操作系统以及您使用“套接字”类访问的服务器软件。我还需要你的“测试用例”。
-
对此真的很抱歉!专家提示;累了不要做任何事情。我想我已经用你需要的一切更新了这个问题。如果我忘记了什么,请告诉我。我真的很感谢你至少考虑帮助@RyanVincent!
-
这看起来已经有足够的信息继续下去了 :-) 我会在接下来的几天里“试一试”,然后告诉你结果。