using System; using System.Net; using System.Net.Sockets; using System.Text; using System.IO; namespace Danga { class UsefulStream { NetworkStream ns; Socket sock; int pos = 0; int size = 0; int BufferSize = 4096; byte[] buf; AsyncCallback readCallback; AsyncCallback onGotLine, onTimeOut; bool wantingLine; // we're fulfilling a BeginGetLine request bool eof; String gotLine; private Encoding lineEnc = Encoding.ASCII; public UsefulStream (Socket sock) { this.sock = sock; ns = new NetworkStream(sock); buf = new byte[BufferSize]; readCallback = new AsyncCallback(this.OnRead); eof = false; } public void Close () { ns.Close(); ns = null; sock.Close(); sock = null; } public void SetEncoder (Encoding en) { lineEnc = en; } public void BeginGetLine (AsyncCallback onGotLine, int msTimeOut, AsyncCallback onTimeOut) { this.onGotLine = onGotLine; this.onTimeOut = onTimeOut; checkForLine(); } public String EndGetLine () { wantingLine = false; return gotLine; } private void ReadMore () { if (eof) return; if (pos > 0 && pos == size) { size = 0; pos = 0; } ns.BeginRead(buf, size, BufferSize-size, readCallback, null); } private void OnRead (IAsyncResult ar) { int bytesRead = ns.EndRead(ar); if (bytesRead == 0) eof = true; //Console.WriteLine("Read {0}: [{1}]", bytesRead, Encoding.ASCII.GetString(buf, size, bytesRead)); size += bytesRead; if (wantingLine) checkForLine(); } private void checkForLine () { wantingLine = true; int i = pos; int npos = -1; while (i < size) { if (buf[i] == (byte)'\n') { npos = i; break; } i++; } //Console.WriteLine("checkForLine: pos={0}, size={1}, npos={2}", pos, size, npos); if (npos == -1) { if (eof) { gotLine = null; // return nulls to client on eof onGotLine(null); return; } // FIXME: may be necessary to move the buffer back first, especially // if we've tried several times now. ReadMore(); return; } gotLine = lineEnc.GetString(buf, pos, npos-pos+1); pos = npos+1; onGotLine(null); } } }