Si bien es cierto que resulta posible establecer sesiones entre clientes y servidores y luego usar una comunicación semidúplex sobre esas sesiones, frecuentemente la elevada sobrecarga ocasionada por múltiples capas de conexión se hace poco atractiva para las aplicaciones donde la performance es crítica, tales como servidores de archivos. Una forma de comunicación sin conexión construida directamente encima de una facilidad de datagramas nativa (especialmente sobre LANs), a menudo, es una elección mucho mejor.
Aún cuando los problemas de performance puede solucionarse usando el modo sin conexiones, el modelo aún tiene sus fallas importantes: la base conceptual de toda comunicación es la de entrada/salida (input/output). Los programas se comunican con otros usando comandos tales como X-DATA.request y X-DATA.indication, el primero de los cuales es I/O y el último de los mismos probablemente sea una interrupción. Ellos difícilmente constituyan la herramienta adecuada para construir aplicaciones bien estructuradas.
Por otros motivos, se ha estado investigando en las universidades y en la industria sobre un modelo radicalmente diferente para el diálogo y el control de errores basado en un servicio sin conexiones. Este trabajo, conocido bajo el nombre de llamadas a procedimientos remotos o RPC (remote procedure calls), ha sido ampliamente implementado en redes y especialmente en sistemas distribuidos.
Las RPCs, a la hora de hablar de servicios de comunicaciones, aunque desde una perspectiva muy diferente, están lógicamente relacionadas con las mismas exigencias que la capa de sesión. Sin embargo, el lector deberá notar a lo largo del estudio que parte del mecanismo está implementado en las capas de presentación y de aplicación.
Comercialmente, el producto NFS mencionado anteriormente proporciona una implementación de RPCs mediante tres módulos: la biblioteca de RPC propiamente dicha (ubicable en el nivel de sesión OSI), una biblioteca de presentación de datos denominada XDR (a nivel de presentación) y la interfaz al usuario junto a otras utilidades (a nivel de aplicación). Vale aclarar que algunos autores tienen una opinión diferente respecto a esta distribución y, más aún, hay ciertos paquetes de software que implementan una idea similar directamente a la capa de aplicación (aunque sea mucho menos eficiente) por lo que algunas veces se lo discute en ese contexto. Por simplicidad, aquí estudiaremos únicamente la filosofía de la propuesta, sin preocuparnos demasiado de su encuadre formal.
La escuela RPC propone el modelo cliente-servidor desde una perspectiva completamente diferente, que ha sido diseñada para ser rápida y transparente. Una RPC es un método de comunicación entre procesos de una red que permite trabajar con un alto nivel de abstracción, ignorando los mecanismos de comunicación subyacentes y las características de su implementación. La política de trabajo surge a partir de la fusión de las ideas directrices del modelo cliente-servidor (muy adecuado en una red) con las del mecanismo de llamada a un procedimiento (muy conocido por los usuarios). Un cliente enviando un mensaje al servidor y obteniendo una réplica se comporta de la misma manera que un programa llamando a un procedimiento y consiguiendo un resultado. En ambos casos, el que llama inicia una acción, espera que se complete y los resultados estén disponibles. Si bien en el caso ordinario (local) el procedimiento corre sobre la misma máquina mientras que con RPCs corre sobre una máquina diferente, quien llama no necesita preocuparse por esta distinción.
Para ayudar a ocultar aún más la diferencia entre llamadas remotas y locales, es posible embeber la RPC en el lenguaje de programación. Supongamos, por ejemplo, que proveemos a cada cliente de un servidor de archivos con un procedimiento de biblioteca read(), que puede llamarse con tres parámetros: un identificador que indica cuál archivo leer, un buffer para almacenar los datos leídos y una cuenta del número de bytes a leer. Una llamada ordinaria a un procedimiento local (es decir, un procedimiento incluido por el linker en el espacio de direcciones de quien llama) toma la forma read(fileid, buffer, count). Este procedimiento podría modificarse adecuadamente de manera que se envíe un mensaje al servidor de archivo y se espere una respuesta. Solamente después que llega la respuesta, read retorna el control a quién efectuó la llamada.
La bondad de este esquema es que la comunicación cliente-servidor ahora toma la forma de llamadas de procedimientos en lugar de comandos de I/O (o peor aún, de interrupciones). Todos los detalles sobre cómo trabaja la red se le pueden ocultar al programa de aplicación poniéndolos en los procedimientos locales tales como el read() modificado. Esos procedimientos son llamados stubs.
En este ejemplo, el procedimiento stub realmente transfiere datos, pero un procedimiento de este tipo también puede enviar un mensaje pidiéndole al servidor que ejecute una operación arbitraria. Por ejemplo, la llamada delete(filename), puede dar lugar a que el procedimiento stub delete() envíe un mensaje al servidor de archivos pidiéndole que destruya el archivo especificado como parámetro. Suministrando los procedimientos stubs apropiados, podemos tener clientes invocando acciones arbitrarias sobre el servidor de una manera mucho más natural para los programadores de aplicaciones que enfrentarse con I/O o con interrupciones. El objetivo final es hacer que las llamadas a procedimientos remotos no parezcan diferentes de las llamadas a procedimientos locales.