Warning: Cannot use a scalar value as an array in /home/admin/public_html/forum/include/fm.class.php on line 757

Warning: Invalid argument supplied for foreach() in /home/admin/public_html/forum/include/fm.class.php on line 770
Форумы портала PHP.SU :: Версия для печати :: socket_write() - Не отправляет более 2х пакетов подряд
Форумы портала PHP.SU » » Работа с сетью » socket_write() - Не отправляет более 2х пакетов подряд

Страниц (1): [1]
 

1. metis - 23 Ноября, 2012 - 08:27:13 - перейти к сообщению
Использую phpSocketDaemon http://code[dot]google[dot]com/p/phpsocketdaemon/
Маленько переиначил его под свои нужды, но функции касающиеся socket_write остались в оригинале.
А теперь проблема - если я в одной функции вызываю socket_write() более двух раз - 3-ий и остальные пакеты в сокет не уходят. При этом возвращаемое значение (количество переданных байтов) каждый раз соответствует размеру пакета, как будто он реально передан в сокет, и отловить непереданные пакеты в коде не получается. Ошибок естественно не возвращается. Сокет не блокируемый.

PHP:
скопировать код в буфер обмена
  1.  
  2. class GlobalServerClient extends socketServerClient {
  3.     public function write($buffer) {
  4.          return parent::write($buffer."\0");
  5.     }
  6. ...
  7. //  здесь мне надо отправить несколько пакетов
  8.     $this->write('1');
  9.     $this->write('2');
  10.     $this->write('3');
  11.     $this->write('4');
  12.     $this->write('5');
  13. ...
  14. }
  15.  
  16. abstract class socketServerClient extends socketClient {...}
  17.  
  18. abstract class socketClient extends socket {
  19.     public $write_buffer   = '';
  20.  
  21.     public function write($buffer)
  22.     {
  23.         $this->write_buffer .= $buffer;
  24.         if ($this->do_write()) return true;
  25.         else return false;
  26.     }
  27.  
  28.     public function do_write()
  29.     {
  30.         $length = strlen($this->write_buffer);
  31.         try {
  32.             $written = parent::write($this->write_buffer, $length);
  33.             // WRITTEN в каждый раз равен LENGTH - проверял.
  34.             if ($written < $length) {
  35.                 $this->write_buffer = substr($this->write_buffer, $written);
  36.             } else {
  37.                 $this->write_buffer = '';
  38.             }
  39.             return true;
  40.         } catch (socketException $e) {
  41.             //обработка ошибки
  42.             return false;
  43.         }
  44.         return false;
  45.     }
  46. }
  47.  
  48. abstract class socket {
  49.     public $socket;
  50.  
  51.     public function write($buffer, $length = 4096)
  52.     {
  53.         if (!is_resource($this->socket)) {
  54.             //обработка ошибки
  55.         } elseif (($ret = @socket_write($this->socket, $buffer, $length)) === false) {
  56.             //обработка ошибки
  57.         }
  58.         return $ret;
  59.     }
  60. }
  61.  


Из отправленных пяти приходят только 2. Кто нибудь знает почему это происходит?
Если кода недостаточно - скажите какая часть интересует, выложу
Подскажите решение или причину.
2. metis - 26 Ноября, 2012 - 08:22:22 - перейти к сообщению
Маленько разобрался.
Каждый вызов write() отправляет данные завершенные нулевым байтом "\0". Если при первом вызове write() отправляется текст "1\0" то при вызове последующих буфер сливается в один и отправляется уже "2\03\04\05\0".
На стороне клиента принимает Flash, который отсекает все после первого отправленного нулевого байта, то есть принимает только "2\0".

Код на клиенте AS3
CODE (text):
скопировать код в буфер обмена
  1. package
  2. {
  3.     import flash.display.Sprite;
  4.     import flash.external.ExternalInterface;
  5.     import flash.events.*;
  6.     import flash.net.Socket;
  7.  
  8.     public class jSocket extends Sprite
  9.     {              
  10.         protected var socket:Socket;
  11.         protected var id:String;
  12.  
  13.         public function jSocket():void {
  14.             // Pass exceptions between flash and browser
  15.             ExternalInterface.marshallExceptions = true;
  16.  
  17.             var url:String = root.loaderInfo.url;
  18.             id = url.substring(url.lastIndexOf("?") + 1);
  19.                        
  20.             socket = new Socket();
  21.             ...
  22.             socket.addEventListener("socketData", onData);
  23.         }
  24.                
  25.         protected function onData(event:ProgressEvent):void{
  26.             ExternalInterface.call("jSocket.flashCallback", "data", id, socket.readUTFBytes(event.bytesLoaded));
  27.         }
  28.     }      
  29. }
  30.  

Помогите плиз, либо сделать чтобы в пхп отправлялся каждый пакет отдельно, либо во флеше чтобы не отбрасывал часть пакета...
3. metis - 27 Ноября, 2012 - 07:43:07 - перейти к сообщению
проблему решил следующим костылем
PHP:
скопировать код в буфер обмена
  1. class GlobalServerClient extends socketServerClient {
  2.     public function write($buffer) {
  3.          return parent::write($buffer."\n"); //изменил
  4.     }
  5. }
  6.  
  7. abstract class socketClient extends socket {
  8.     public $write_buffer   = '';
  9.  
  10.     public function write($buffer)
  11.     {
  12.         $this->write_buffer .= $buffer;
  13.         return true; //изменил
  14.     }
  15.  
  16.     public function do_write()
  17.     {
  18.         $length = strlen($this->write_buffer);
  19.         try {
  20.             $written = parent::write($this->write_buffer."\0", $length+1); //изменил
  21.             if ($written < $length+1) { //изменил
  22.                 $this->write_buffer = substr($this->write_buffer, $written);
  23.             } else {
  24.                 $this->write_buffer = '';
  25.             }
  26.             return true;
  27.         } catch (socketException $e) {
  28.             //обработка ошибки
  29.             return false;
  30.         }
  31.         return false;
  32.     }
  33. }


на стороне клиента
CODE (AS3):
скопировать код в буфер обмена
  1. protected function onData(event:ProgressEvent):void{
  2.     var len:uint = event.bytesLoaded;
  3.     var data:String = socket.readUTFBytes(len);
  4.     var array:Array = data.split("\n");
  5.     for (var i:uint = 0; i<array.length; i++) {
  6.         if(array[i] != "") {
  7.             ExternalInterface.call("jSocket.flashCallback", "data", id, array[i]);
  8.         }
  9.     }
  10. }


Смысл: то есть если я раньше пользовался нулевым байтом как разделителем для своих команд, то сейчас придется использовать перенос строки, а нулевой байт оставить для флэша, как конец пакета. Это конечно не идеальное решение и придется теперь учитывать это в коде и заменять перенос строки на сервере и подставлять обратно на клиенте, чтобы не возникло проблем. Муторно, но другого способа не нашел. Может кому и это пригодится.

Спасибо всем за помощь! *FOREVER ALONE*

ЗЫ. Чуть не забыл, функцию do_write я теперь вызываю в бесконечном цикле, в файле где инициализирую данных клиентов и обрабатываю их ответы. То есть за цикл буфер собирает все команды которые сервер должен отправить клиенту, и в конце цикла отправляет их.

 

Powered by ExBB FM 1.0 RC1