У меня были проблемы с чтением данных с сервера сокетов Python. Я попробовал несколько методов и искал решение в течение нескольких месяцев.
Ответ, который я пытаюсь получить от сервера сокетов Python, каждый раз отличается. Это может быть 40 символов в первый раз и более 10 000 символов в следующий.
Я пытался использовать 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. Просто основной должен работать только для проверки этого. Даже без зависимостей. Что-то вроде этот работает.
Для PHP я использую Вамп а также 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. После отправки команды на сервер сокетов, он отправляет ответ с запрошенными данными. Сокет сервер должен затем закройте соединение. И вот где проблема была. Он отправлял ответ, но не закрывал соединение, поэтому все, что мне нужно было сделать, это закрыть соединение после каждой команды. Время отклика прошло с 2,02 секунд до 20мс, что я и хотел
Других решений пока нет …