2012-09-03 6 views
31

PHP tiene dos API diferentes para interactuar con sockets. Existe la API de bajo nivel de socket que básicamente envuelve la API de socket C. Y está la API de sockets de flujo de alto nivel, que implementa la interfaz de flujo de PHP.Conversión de un recurso de socket en un socket de secuencia

Desafortunadamente, la API de socket de flujo no admite la configuración de opciones de socket de bajo nivel. Sin embargo, esto es algo que tengo que hacer. Del mismo modo, la API de socket no admite el uso de llamadas a funciones estándar como fread, fwrite y fclose, por lo que es incompatible con el resto de mi código.

PHP 5.4 introdujo la función socket_import_stream. Esto le permite tomar un socket de flujo y obtener el recurso socket subyacente. Mi plan era usar esto para crear el socket de flujo, obtener el socket, establecer algunas opciones en él y luego continuar usando el socket de flujo original.

La razón por la que esto no funcionó para mí es que necesito establecer las opciones antes del enlace. La única forma de vincular un socket de flujo es usar stream_socket_server, que ya realiza el enlace. Es por eso que no pude usarlo.

Ahora estoy buscando el inverso de socket_import_stream, por lo que puedo convertir mi recurso de socket en un socket de flujo. No he podido encontrar esa función, pero espero que algunas personas muy inteligentes puedan ayudarme. O envíe un parche a la fuente PHP que lo hace. O dame pistas sobre cómo escribir un parche.

EDITAR: Tengo un código que actúa en una secuencia de PHP para analizar paquetes DNS de la misma. Quiero volver a utilizar ese código con un socket habilitado para multidifusión. No puedo habilitar la multidifusión en un socket de flujo, y no puedo usar las funciones de flujo en un socket sin procesar.

EDIT2: Quiero usar esta secuencia con stream_select, por lo que las envolturas de flujo personalizadas no son una opción, desafortunadamente.

+7

Comentario del código fuente de PHP: 'mantenga una referencia zval a la transmisión (también puede hacerse un php_stream * directamente, pero esto podría ser un poco mejor si en el futuro queremos proporcionar un socket_export_stream)' https: // bitbucket.org/php/php-src/src/0ef8b095ccda/ext/sockets/sockets.c#cl-2524 Supongo que 'socket_export_stream' es la función que está buscando, desafortunadamente parece que todavía no está implementado. – umpirsky

+3

Usted solo está presentando los problemas que encontró al implementar una "solución" a un problema no descrito.Exponga el problema original también, tal vez haya otras formas. –

+0

@ Tiberiu-IonuţStan He agregado más información sobre mi problema. – igorw

Respuesta

6

Puede usar la función stream_wrapper_register en combinación con una clase que implementa la plantilla streamWrapper para crear una secuencia de socket de multidifusión. Esto le permitirá aprovechar todas las funciones de flujo integradas, aunque no es tan conveniente como socket_export_stream.

+0

Esta es la solución correcta. Como hay mucho que puedes hacer con un socket, implementar el contenedor debería ser trivial. – cleong

+0

Esto ayuda un poco, sin embargo, hay un problema con esta solución. Las transmisiones personalizadas no se pueden usar con 'stream_select', porque no hay forma de extraer el descriptor del archivo. Agregando esto a la pregunta ahora. – igorw

+0

¿Podemos usar un acceso directo a los descriptores de archivos como 'php: // fd/N' para determinar el actual que es nuestro? – lisachenko

5

La razón por la que esto no funcionó para mí es que necesito establecer las opciones antes de encuadernar. La única forma de vincular un socket de flujo es usar stream_socket_server, que ya realiza el enlace. Es por eso que no pude usarlo.

El cuarto parámetro de stream_socket_server() es $flags, que por defecto es STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, por lo que no se ommit, dan 0 (u otro banderas).

Después de todo ajuste se realiza, aún puede enlazar de forma manual (& escuchar) que toma utilizando socket_bind() & socket_listen().

No lo intenté, solo una idea.

+0

@Leigh No es cierto, tenga en cuenta '== 0' en la segunda línea que ha vinculado. – igorw

+0

@igorw Tienes razón, por alguna razón, pensé que en realidad estaba haciendo '& ~ STREAM_XPORT_SERVER' para recuperar los indicadores originales, y comprobarlo en 0, que es lo que' STREAM_XPORT_CLIENT' se define como. Por lo tanto, una bandera de 0 saltará la porción bind/listen. – Leigh

+0

Esta fue una gran idea, pero desafortunadamente 'socket_import_stream' intenta obtener la familia de socket, que no existe al crear el servidor sin flags. Obtengo "Advertencia: socket_import_stream(): no se puede obtener la familia de socket [9]: Descriptor de archivo incorrecto". – igorw