¡Esta es una revisión vieja del documento!
System.Net.Sockets.TcpListener server = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Any, 2005); server.Start(); Byte[] bytes = new Byte[256]; String data = null; while (true) { System.Net.Sockets.TcpClient client = server.AcceptTcpClient(); data = null; System.Net.Sockets.NetworkStream stream = client.GetStream(); int i; while ((i = stream.Read(bytes, 0, bytes.Length)) != 0) { data = System.Text.Encoding.ASCII.GetString(bytes, 0, i); Console.WriteLine("Received: {0}", data); data = data.ToUpper(); byte[] msg = System.Text.Encoding.ASCII.GetBytes(data); stream.Write(msg, 0, msg.Length); Console.WriteLine("Sent: {0}", data); } }
Para enviar un “salto de línia” haremos:
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data + "\n\r"); stream.Write(msg, 0, msg.Length);
En System.Text.RegularExpressions existe la clase Regex que se encarga de localizar combinaciones (matches) de expresiones regulares en un texto. Por ejemplo, su método estático Matches recibe un texto y una expresión regular y devuelve objetos Match de las coincidencias.
Un objeto Match tiene las siguientes propiedades interesantes:
NextMatch(): Index: Posición dentro del string original donde se encuentra el primer carácter de la coincidencial.Lenght:Success:Value: Recoge el substring de la coincidencia encontrada.string startBy = "src=\"|src = \"|src= \"|src =\""; var matches = System.Text.RegularExpressions.Regex.Matches(text, startBy, System.Text.RegularExpressions.RegexOptions.IgnoreCase); List<string> lImgNames = new List<string>(); for (int i = 0; i < matches.Count; i++) { var match = matches[i]; int start = match.Index + match.Value.Length; int end = text.IndexOf("\"", start); string file = text.Substring(start, end - start); lImgNames.Add(file); }
Son utilizados para realizar una comunicación entre procesos que están corriendo en la misma máquina (IPC, inter-process communication). Y son más rápidos que utilizar rutinas sobre red, son algo parecidas a las Named Pipes existentes en el kernel32.dll.
Para poder usar dichos canales se necesitan los siguientes elementos:
También necesitaremos agregar una referencia a System.Runtime.Remoting. Y hacer using de unos cuantos namespaces:
using System.Runtime.Remoting.Channels.Ipc; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting;
Un dominio de aplicación es un proceso dentro del sistema operativo donde una o más aplicaciones residen. Los objetos que se encuentran en el mismo dominio de aplicación se comunican directamente, en cambio, los que están en distintos dominios se comunican a partir del transporte de copias de estos objetos. Existe una clase (System.MarshalByRefObject) que sirve como clase base para las clases que intervengan la comunicación e intercambio de mensajes entre dominios de aplicación (si no heredasen serían marshal by value).
Necesitaremos crear la clase de los objetos que se compartirán (ha de heredar de MarshalByRefObject).
namespace SharedObjects { public class Class1 : MarshalByRefObject { string v; public string Value { get { return this.v; } set { this.v = value; } } } }
Creamos un canal de servidor a partir de un nombre de canal (en formato string) y lo registramos mediante el método estático de la clase ChannelServices, a este se le pasan dos objetos, un objeto correspondiente al canal en sí y un boolean, que será true si el canal será manejado a partir de un protocolo seguro.
Luego deberemos registrar los objetos compartidos a partir del método estático RegisterWellKnownServiceType dentro de RemotingConfiguration, si lo hacemos mediante WellKnownObjectMode.Singleton se creará un único objeto objeto, para acceder a él la ruta será ipc://nombreDelCanal/NombreDelObjeto.
Para recoger un objeto utilizaremos el método GetObject de la clase Activator.
IpcServerChannel server = new IpcServerChannel("myChannel"); ChannelServices.RegisterChannel(server, false); RemotingConfiguration.RegisterWellKnownServiceType(typeof(SharedObjects.Class1), "sharedObjs", WellKnownObjectMode.Singleton); SharedObjects.Class1 c = (SharedObjects.Class1)Activator.GetObject(typeof(SharedObjects.Class1), "ipc://myChannel/sharedObjs"); c.Value = "Servidor";
Únicamente es necesario acceder al objeto a partir de Activator.GetObject.
// IpcClientChannel icc = new IpcClientChannel(); // ChannelServices.RegisterChannel(icc, true); // RemotingConfiguration.RegisterWellKnownClientType(typeof(SharedObjects.Class1), "ipc://myChannel/sharedObjs"); SharedObjects.Class1 c = (SharedObjects.Class1)Activator.GetObject(typeof(SharedObjects.Class1), "ipc://myChannel/sharedObjs"); Console.WriteLine(c.Value);
El fichero que configura la aplicación es el app.config y se ha de encontrar en el directorio donde está el ensamblado ejecutable de la aplicación.
Para leer el valor logFile de un fichero de configuración como el que sigue:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <appSettings> <add key="logFile" value="log.txt"/> </appSettings> </configuration>
Utilizaremos un objeto de la clase AppSettingsReader y su método GetValue:
(string)new System.Configuration.AppSettingsReader().GetValue("dbFile", typeof(String));
Podemos agregar secciones personalizadas al fichero, por ejemplo una sola para el tema de log, para ello deberemos declararla entro de la tag configSections indicando nombre y tipo como sigue:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <section name="log" type="System.Configuration.DictionarySectionHandler" /> </configSections> <appSettings> </appSettings> <log> <add key="logFile" value="log.txt"/> </log> </configuration>
Para leer estas secciones deberemos agregar la referencia al ensamblado System.Configuration y poder así utilizar la clase ConfigurationManager:
IDictionary confTable = (IDictionary)System.Configuration.ConfigurationManager.GetSection("log"); string logFile = (string)confTable["logFile"];
Podemos agregar grupos de secciones, por ejemplo:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="atm.ws"> <section name="dbInfo" type="System.Configuration.DictionarySectionHandler" /> </sectionGroup> </configSections> <atm.ws> <dbInfo> <add key="DataSource" value="TheDataSource" /> <add key="UserName" value="user" /> <add key="Password" value="pass" /> </dbInfo> </atm.ws> ...
Y luego acceder a ellas como si accediesemos a una sección personalizada:
IDictionary confTable = (IDictionary)System.Configuration.ConfigurationManager.GetSection("atm.ws/dbInfo"); string dataSource = (string)confTable["DataSource"];