2010-04-20 14 views
9

Hay dos enchufes conectados. ¿Cómo puedo interconectarlos?¿Cómo puedo "interconectar" dos enchufes en Linux?

  1. Los datos aparecidos en un socket deben escribirse en el otro.
  2. EOF/FIN debe propocionarse bien. Si uno está medio cerrado, el otro también debe estar medio cerrado.
 
int client = get_connected_client_socket(); 
int proxy = get_connected_proxy_socket(); 
negotiate_with_proxy(proxy); 
iterconnect(client, proxy); 
// Now forgot about both client and proxy. 
// System should handle IO/shutdown/close. 
// Ideally even without any support of the user-space process. 

Puede Linux hacerlo? ¿Se puede hacer engañando el seguimiento de la conexión para cambiar el estado de seguimiento de la conexión existente?

@related Determine how much can I write into a filehandle; copying data from one FH to the other

Respuesta

4

Conoce splice(). En función de sus dos preguntas, I , piense, aquí es donde se dirige. La última vez que verifiqué, no puede hacer esto en una llamada de empalme porque los descriptores de ambos archivos no pueden ser zócalos. Pero deberías poder hacerlo en 2 llamadas (sockin-> pipe-> sockout). También echa un vistazo a tee(). Puede que no sean exactamente lo que quieres, pero por lo que puedo imaginar, están en el estadio.

+0

No, no tenía conocimiento de 'empalme' (solo teóricamente sabía sobre' sendfile'). Lo pensaré y lo probaré. –

+0

socket -> pipe -> socket 'splice' chain funciona. –

+0

@Vi .: ¿Supongo que usabas sockets TCP? Parece que este enfoque no funcionará para sockets UDP? –

0

socket de dominio Unix puede ayudar. Consulte la página de manual:

man unix 
+0

No se encontró nada útil en 'man 7 unix'. Quiero que mis enchufes ganen inter-influencias similares a las que tienen los zócalos 'socketpair'. Espero que 'interconnect' funcione con sockets TCP, UNIX y descriptores de archivos. –

2

Necesitará un proceso de espacio de usuario para quedarse y copiar datos de un socket al otro. Es bastante sencillo, aunque:

  • read Cualquier dato desde el zócalo A, write A la toma de B;
  • Cualquier dato read del zócalo B, write al zócalo A;
  • Si read devuelve 0 en el socket A, llame al shutdown(SHUT_WR) en el socket B;
  • Si read devuelve 0 en el socket B, llame al shutdown(SHUT_WR) en el socket A;
  • Una vez que ambos sockets han devuelto 0 de lectura, close ambos enchufes y salida;
  • Si cualquiera de los receptáculos devuelve EPIPE, close ambos enchufes y sale.

Como Newton Falls menciones, puede utilizar splice() hacer esto de una manera copia cero, pero eso es sólo una mejora de rendimiento; obténgalo trabajando con read/write primero. Debería poder solo fork() de un niño hacer esto, lo que lo hará "disparar y olvidar" para su proceso principal.

+0

Parece que 'empalme' es lo que puede ayudar. 'write' no es bueno, porque puede escribir menos de lo que solicité y debo guardar el resto en alguna parte. 'fork' no es bueno, debido a una nueva conexión => nuevo proceso, también necesita un manejo cuidadoso de FD (heredado/no heredado). –

+0

Como dije, 'splice()' es solo una mejora del rendimiento, también puede empalmar menos de lo que solicitaste, y no hará que 'fork()' sea más o menos útil (aún tienes que mantener 'splice () 'hasta que la conexión haya terminado). – caf

+0

Si el empalme empalma menos de lo solicitado, el resto ('size_I_requested - size_actually_spliced') permanecerá en un FD leído, por lo que puedo empalmarlo más tarde cuando la salida se desbloqueará sin almacenar los datos en mi proceso. Así que se usará el buffer de tuberías y no necesito asignar/desasignar cosas en mi programa. –

0

Verifique la herramienta socat. Esa es la mejor herramienta para resolver este tipo de problemas.

+1

Lo sé y lo uso a menudo. Pero la pregunta es acerca de cómo hacerlo en el programa. Engendrar 'socat - -' para esto es demasiado derrochador. –

Cuestiones relacionadas