[csmaild-cvs] csmaild/src/Common/NetworkManager Connection.cs,NONE,1.1 Listener.cs,NONE,1.1 NetworkM
Brought to you by:
tamc
|
From: <ta...@us...> - 2003-07-30 22:44:46
|
Update of /cvsroot/csmaild/csmaild/src/Common/NetworkManager In directory sc8-pr-cvs1:/tmp/cvs-serv17123/src/Common/NetworkManager Added Files: Connection.cs Listener.cs NetworkManager.cs Log Message: Never actually moved these, I deleted them from Imap, but never cvs added them to Common, oops --- NEW FILE: Connection.cs --- using System; using System.Collections; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; using System.Text; namespace Imap.NetworkManager { public delegate void ReceivedLineDelegate(Connection con, string line); public delegate void ConnectionClosedDelegate(Connection con); /// <summary> /// Represents a single client connection /// </summary> public class Connection { #region Variables private Socket mClient; // the communication socket private NetworkStream mSocketStream; // a stream wrapping the communication socket private byte[] mReceiveBuffer; // a small storage place for receiving bytes for the line private StringBuilder mReceivedString; // used to store the line that we have received private Listener mListener; // the listener that created us #endregion #region Events private event ReceivedLineDelegate mReceivedLineEvent; private event ConnectionClosedDelegate mConnectionClosedEvent; /// <summary> /// Fires when the asynchronously requested line has been received from the client /// </summary> public event ReceivedLineDelegate ReceivedLineEvent { add { mReceivedLineEvent += value; } remove { mReceivedLineEvent -= value; } } /// <summary> /// Fires when the connection is closed remotely /// </summary> public event ConnectionClosedDelegate ConnectionClosedEvent { add { mConnectionClosedEvent += value; } remove { mConnectionClosedEvent -= value; } } #endregion #region Constructor /// <summary> /// Creates a new Connection object /// </summary> /// <param name="client">The Socket for this Connection</param> /// <param name="listener">The Listener that created us</param> internal Connection(Socket client, Listener listener) { mClient = client; mListener = listener; mSocketStream = new NetworkStream(mClient, true); mReceiveBuffer = new byte[8192]; mReceivedString = new StringBuilder(1024); // so the initial few growings don't have to happen } #endregion #region Public methods /// <summary> /// Writes the message to the socket /// </summary> /// <param name="msg">The message to write</param> public void Write(string msg) { if(mClient.Connected) { byte[] b = Encoding.ASCII.GetBytes(msg); mSocketStream.Write(b, 0, b.Length); } } /// <summary> /// Writes the message to the socket /// </summary> /// <param name="msg">The message to write (it will be suffixed with a CRLF)</param> public void WriteLine(string msg) { System.Diagnostics.Trace.WriteLine(ToString() + " <- " + msg); Write(msg + "\r\n"); } /// <summary> /// Reads a line from the socket asynchronously /// </summary> public void BeginReadLine() { if(mClient.Connected) mSocketStream.BeginRead(mReceiveBuffer, 0, mReceiveBuffer.Length, new AsyncCallback(ReceiveLineCallback), null); } public string ReadLine() { while(true) { // we may have enough information for a line from the last read string currentData = mReceivedString.ToString(); // TODO: this happening everytime could be a performance hit int idx = currentData.IndexOf("\r\n"); // yay, found the line if(idx != -1) { // we quite possibly got too much data for this line // get the line, leave the rest in the string builder string line = currentData.Substring(0, idx); mReceivedString.Remove(0, idx+2); // remove the line and the \r\n return line; } else // read more { int read = mSocketStream.Read(mReceiveBuffer, 0, mReceiveBuffer.Length); if(read == 0) // connection was closed { OnClosed(); return null; } else { string incoming = Encoding.ASCII.GetString(mReceiveBuffer, 0, read); mReceivedString.Append(incoming); } } } } /// <summary> /// Reads a block from the socket /// </summary> /// <param name="block">The buffer to place the bytes read</param> /// <param name="offset">The offset into this buffer</param> /// <param name="size">The number of bytes to read into the buffer</param> /// <param name="callback">The callback function to call after done reading</param> public void ReadBlock(byte[] block, int offset, int length) { int read = 0; if(mReceivedString.Length > 0) { // TODO: this could probably be made slightly more efficient byte[] currentData = System.Text.Encoding.ASCII.GetBytes(mReceivedString.ToString()); int toCopy = Math.Min(length, currentData.Length); // get the number of bytes we'll need mReceivedString.Remove(0, toCopy); Array.Copy(currentData, 0, block, offset, toCopy); read += toCopy; } while(read != length) { int readThisTime = mSocketStream.Read(block, offset+read, length-read); if(readThisTime == 0) // connection was closed { OnClosed(); return; } else read += readThisTime; } } #endregion #region Protected methods protected void OnReadLine(string line) { if(mReceivedLineEvent != null) mReceivedLineEvent(this, line); } /// <summary> /// Fires when the socket is closed /// </summary> protected virtual void OnClosed() { mClient.Close(); mSocketStream.Close(); if(mConnectionClosedEvent != null) mConnectionClosedEvent(this); } #endregion #region Private methods private void ReceiveLineCallback(IAsyncResult result) { int read = mSocketStream.EndRead(result); if(read == 0) // connection was closed { // spill event OnClosed(); } else { // if we're reading a line string incoming = Encoding.ASCII.GetString(mReceiveBuffer, 0, read); mReceivedString.Append(incoming); // we're reading a line and we found the end of the line!! string currentData = mReceivedString.ToString(); // TODO: this happening everytime could be a performance hit int idx = currentData.IndexOf("\r\n"); if(idx != -1) { // we quite possibly got too much data for this line // get the line, leave the rest in the string builder string line = currentData.Substring(0, idx); mReceivedString.Remove(0, idx+2); // remove the line and the \r\n if(line != string.Empty) System.Diagnostics.Trace.WriteLine(ToString() + " -> " + (string)line); // spill event OnReadLine(line); } else // read more BeginReadLine(); } } #endregion #region Overridden methods public override string ToString() { return mClient.RemoteEndPoint.ToString(); } #endregion } } --- NEW FILE: Listener.cs --- using System; using System.Net; using System.Net.Sockets; namespace Imap.NetworkManager { public delegate void AcceptDelegate(Connection con); /// <summary> /// Simple event based listener class /// </summary> public class Listener { private Socket mListenSocket; private event AcceptDelegate mAcceptedConnection; public event AcceptDelegate AcceptedConnection { add { mAcceptedConnection += value; } remove { mAcceptedConnection -= value; } } public Listener(int port) { // create a TCP socket on the specified port mListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); mListenSocket.Bind(new IPEndPoint(IPAddress.Any, port)); // start listening for connections, handle this asynchronously mListenSocket.Listen(10); // TODO: configurable/global backlog mListenSocket.BeginAccept(new AsyncCallback(AcceptCallback), null); } private void AcceptCallback(IAsyncResult result) { if(mListenSocket == null) return; // do the final accpet and wait for another Connection con = new Connection(mListenSocket.EndAccept(result), this); mListenSocket.BeginAccept(new AsyncCallback(AcceptCallback), null); // tell the observers about our new connection if(mAcceptedConnection != null) mAcceptedConnection(con); } } } --- NEW FILE: NetworkManager.cs --- using System; using System.Collections; using System.Net; using System.Text; namespace Imap.NetworkManager { /// <summary> /// A facade for network management related tasks /// </summary> public class NetworkManager { private ArrayList mConnections; private ArrayList mListeners; public NetworkManager() { mConnections = new ArrayList(); mListeners = new ArrayList(); } /// <summary> /// Starts a listening socket on the specified port /// </summary> /// <param name="port">The port to listen on</param> /// <returns>The created listener</returns> public Listener StartListener(int port) { Listener li = new Listener(port); li.AcceptedConnection += new AcceptDelegate(Listener_AcceptedConnection); mListeners.Add(li); return li; } public Connection StartConnection(IPAddress address, int port) { // TODO: implement if the need to start connections arises throw new NotImplementedException("Not yet buD!!!"); } public void Listener_AcceptedConnection(Connection con) { con.ConnectionClosedEvent += new ConnectionClosedDelegate(Connection_Closed); mConnections.Add(con); } public void Connection_Closed(Connection con) { mConnections.Remove(con); } } } |