C# MemoryStream, NetworkStream, CryptoStream

MemoryStream Sınıfı

Uygulamanızın sık sık veriye ihtiyaç duyduğu durumlarda verileri dosya (file)’da tutmak uygulamanızın performansını düşürür ve arayüzün yanıt süresini geciktirir. Örneğin uygulamanız bir veri kümesinden sıklıkla bir referans veriye ihtiyaç duyduğu zaman bu veri kümesini dosyada tutmak doğru bir seçim olmaz. Bu gibi durumlarda veriyi dosya yerine MemoryStream’de saklamak daha efektif bir çözüm olmaktadır. Çünkü MemoryStream geçici veri saklama işleminde veriyi bellekte sakladığından hızlı depolama imkanı sunmaktadır.

Uygulamanız içerisinde serileştirmiş olduğunuz nesneleri transfer ederken geçiçi olarak MemoryStream de saklamak bu duruma iyi bir örnek olarak gösterilebilir. Böyle bir durumda FileStream veya BufferedStream kullanmak yerine MemoryStream kullanmak daha iyi bir performans sağlayacaktır. MemoryStream nesnesi oluşturmak FileStream yada BufferedStream’e göre biraz farklıdır. Instance oluşturma işlemi bir kaç yolla yapılabilmektedir. Aşağıdaki kodda MemoryStream nasıl oluşturulur ve WriteTo() metodu kullanılarak bu stream’e nasıl verileri yazabileceğimizi örnekleyelim.

static void Main(string[] args)
{
    // Boş Memory stream oluşturuluyor.
    MemoryStream mS = new MemoryStream();
    byte[] memData = Encoding.UTF8.GetBytes("Belleğe (Memory) yazılacak veri.");
    // Veriler yazılıyor.
    mS.Write(memData, 0, memData.Length);
    // Pointer pozisyonu en başa alınıyor.
    mS.Position = 0;
    byte[] inData = new byte[100];
    // Bellekten okunuyor.
    mS.Read(inData, 0, 100);
    Console.WriteLine(Encoding.UTF8.GetString(inData));
    Stream strm = new FileStream(@"C:\MemOutput.txt", FileMode.OpenOrCreate, FileAccess.Write);
    mS.WriteTo(strm);
    Console.ReadLine();
}

Örnek uygulamayı buradan indirebilirsiniz.

NetworkStream Sınıfı

Ağ (Network) üzerinde bir lokasyondan diğer bir lokasyona veriler akışkan bir formda yada stream olarak transfer edilmektedir. Böyle ağ üzerinde veriyi ağ soketleri (network sockets) üzerinden transfer edeecek stream işlemlerini yapan NetworkStream sınıfı System.Net.Sockets namespace’i içerisinde .Net ile hazır gelmektedir.

NetworkStream unbuffered bir stream olduğu için verilere rasgele bir erişim şağlanamayaz yada pozisyon değiştirilemez. Seek() metodu ve Position özelliği kullanıldığında ise hata (exception) alınır. CanSeek özellğine bakıldığında ise her zaman false değeri döner.

NetworkStream’in bazı önemli özellikleri :

DataAvailable : Geri dönüş değeri olarak Boolean dönen bu özellik sayesinde stream içerisindeki verinin okunabilir durumda olup olmadığını döndürür. Geri dönüş değeri true ise veriler okunabilir durumdadır.
Readable : Bu özellik sayesinde stream üzerinde okuma yetkimizin olup olmadığı kontrol edilir. Diğer stream sınıflarındaki CanRead özelliği ile aynı işlevi yerine getirmektedir.
Socket : Üzerinde çalıştığı Socket bilgisini verir.
Writeable : Bu özellik sayesinde stream üzerin yazma işlemi yapılıp yapılamayacağı kontrol edilir. Diğer stream sınıflarındaki CanWrite özelliği ile aynı işlevi yerine getirmektedir. Geri dönüş değeri true ise stream’e veri yazılabilir.

Her NetworkStream yükleyicisi (constructor) en azından bir Socket bilgisine ihtiyaç duyar, bunun yanında ek olarak boolean değerinde ownership ve/veya (FileStream yazısında açıklamış olduğum) veri yazma izni için FileAccess enumeration değerlerini alabilmektedir. Ownership flag’ine true değerini vererek NetworkStream nesnesinin socket’i üzerinde tam kontrol sağlanmış olur ve istenirse Close() metodu kullanılarak üzerinde çalışılan Socket kapatılabilir.

TcpClient sınıfı kullanılarak yapılan veri iletişimde NetworkStream kullanılmaktadır. Yapacağımız örnek client-server senaryoda iletişim için TcpClient sınıfını kullanılacağız ve veri iletişimindede NetworkStream kullanmış olacağız. TcpClient.GetStream() metodu dönüş değeri olarak Socket ve yükleyici (constructor) parametrelerine bağlı olarak yeni bir NetworkStream nesnesi oluşturarak göndermektedir.

System.Net.Sockets namespace’inde yer alan TCPListener yardımıyla oluşturulan server (listener) kodları aşağıdaki gibidir :

static void Main(string[] args)
{
    try
    {
        // TCP listener oluşturuluyor.
        TcpListener listener = new TcpListener(new System.Net.IPAddress( new byte[] {127,0,0,1}), 
                                                                         6006);
        listener.Start();
        Console.WriteLine("TcpListener oluşturuldu client bekleniyor.");
        TcpClient tc = listener.AcceptTcpClient();
        NetworkStream stm = tc.GetStream();
        byte[] readBuf = new byte[100];
        stm.Read(readBuf, 0, 100);
        // Veriler görüntüleniyor.
        Console.WriteLine(Encoding.UTF8.GetString(readBuf));
        stm.Close();
        Console.ReadLine();
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
    }
}     

Bu senaryoda veriyi server (listerner)’a gönderecek TCPClient kullanılarak yapılan client uygulamada aşağıdaki gibi olacaktır :

Bu noktada Client uygulamayı çalıştırmadan önce server (listener) uygulamasının çalıştırılması gerektiğini unutmamak gerekir!

static void Main(string[] args)
{
    try
    {
        // TCP Client oluşturuluyor.
        TcpClient client = new TcpClient();
        // Hostname ve port bilgileri kullanılarak listener'a bağlanılıyor.
        client.Connect("localhost", 6006);
        // Verileri göndermek için NetworkStream instance'ı oluşturuluyor.
        NetworkStream stm = client.GetStream();
        byte[] sendBytes = Encoding.UTF8.GetBytes("Bu veri client uygulamadan gönderilmiştir.!!!");
        stm.Write(sendBytes, 0, sendBytes.Length);
        client.Close();
        Console.WriteLine("Tcp client uygulamasından veri gönderilmiştir.");
        Console.ReadLine();
    }
    catch (Exception e)
    {
        Console.WriteLine(e.ToString());
        Console.WriteLine("Muhtemelen listener uygulaması başlatılmamıştır.");
    }
}

Örnek uygulamayı buradan indirebilirsiniz.

CryptoStream Sınıfı

Bazı veri tipleri için, veriyi şifreleyip saklamak veya güvenli bir şekilde transfer etmek önemli bir işlemdir. Veriyi güvenli bir biçimde saklamak yada transfer etmek için genellikle gizli bir anahtar (secret key) ile şifreleyip (encrypt) bu işlemleri verinin okunamadığı bir formda gerçekleştirmek gerekir. Şifreli formdaki okunamayan veri, gizli anahtar (secret key) sayesinde şifresi çözümlenip (decrypt edilip) normal formuna döndürülür ve istenilen işlemler gerçekleştirilebilir. Şifreleme alagoritmasına bağlı olarak gizli anahtar (secret key) şifreleme (encryption) yada şifre çözümleme (decryption) işlemlerinde güvenlik nedeni ile aynı olmayabilir.

.Net içerisinde yer alan CryptoStream sınıfı sayesinde stream’ler birbiri arasında kriptografik dönüşümler yapılarak daha güvenli bir formatta saklanabilir yada transfer edilebilir. CryptoStream sınıfı System.IO namespace’i içerisinde yer almamasına rağmen Stream sınıfından türemiştir. CryptoStream yükleyicisi (constructor’ı) üç parametre almaktadır. Bunlardan ilki kriptografik işlemle şifrelenecek yada şifresi çözümlenecek stream nesnesidir, ikinci parametresi ise şifreleme (encrypt) işlemini yapacak provider’dır, son parametre ise cryptographic stream üzerinde yazma yada okuma işleminin yapılıp yapılamayacağını bildiren parametredir.

Kriptografik dönüşüm işlemlerini yapacak ICryptoTransform interface’ini miras alan çeşitli servis provider’lar .Net içerisinde kullanıma hazır halde gelmektedir. Örneğimizde de System.Security.Cryptography namaspace’i içerisinde yer alan bu kriptografik servis provider’larından seçimimize bağlı olarak istediğimiz provider’a kriptografik işlemleri yaptıralım :

static void Main(string[] args)
{
    Console.WriteLine("CryptoStream için Service Provider seçiniz :");
    Console.WriteLine("1 = DESCryptoServiceProvider");
    Console.WriteLine("2 = RC2CryptoServiceProvider");
    Console.WriteLine("3 = RijndaelManaged");
    Console.WriteLine("4 = TripleBESCryptoServiceProvider");
    Console.WriteLine("5 = SymmetricAlgorithm");
    // Şifreleme algoritması oluşturuluyor.
    SymmetricAlgorithm des = null;
    switch (Console.ReadLine())
    {
        case "1":
            des = new DESCryptoServiceProvider();
            break;
        case "2":
            des = new RC2CryptoServiceProvider();
            break;
        case "3":
            des = new RijndaelManaged();
            break;
        case "4":
            des = new TripleDESCryptoServiceProvider();
            break;
        case "5":
            des = SymmetricAlgorithm.Create(); 
            break;
    }

    FileStream fs = new FileStream("GizliDosya.dat", FileMode.Create, FileAccess.Write);
    ICryptoTransform desencrypt = des.CreateEncryptor();
    CryptoStream cryptostream = new CryptoStream(fs, desencrypt, CryptoStreamMode.Write);
    string theMessage = "Çok gizli mesaj";
    byte[] bytearrayinput = Encoding.UTF8.GetBytes(theMessage);
    Console.WriteLine("Orjinal Mesaj : {0} ", theMessage);
    cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
    cryptostream.Close();
    fs.Close();

    // Decrypt işlemi
    // File stream'den encrypt edilmiş mesaj okunuyor.
    FileStream fsread = new FileStream("GizliDosya.dat", FileMode.Open, FileAccess.ReadWrite);
    byte[] encByte = new byte[fsread.Length];
    fsread.Read(encByte, 0, encByte.Length);

    // Okuma işlemi gerçekleştirildikten sonra FileStream pozisyonu 0 olarak güncelleniyor.
    Console.WriteLine("Encrypt edilmiş mesaj : " + Encoding.UTF8.GetString(encByte));
    fsread.Position = 0;

    // Seçtiğimiz Service Provider'a göre  okunan script Decrypt ediliyor.
    ICryptoTransform desdecrypt = des.CreateDecryptor();
    CryptoStream cryptostreamDecr = new CryptoStream(fsread, desdecrypt, CryptoStreamMode.Read);
    byte[] decrByte = new byte[fsread.Length];
    cryptostreamDecr.Read(decrByte, 0, (int)fsread.Length);
    string output = Encoding.UTF8.GetString(decrByte);
    Console.WriteLine("Decrypted edilmiş mesaj : {0}", output);
    cryptostreamDecr.Close();
    fsread.Close();

    Console.ReadLine();
}

Örnek uygulamayı buradan indirebilirsiniz.

Kaynak ;

MemoryStream Class
NetworkStream Class
CryptoStream Class

Bir cevap yazın