İçeriğe geç

C# ile Asenkron Socket Programlama

Kimine göre eskide kalmış olsa da, hala birçok yerde aktif olarak kullanılan soket programlamadan bahsedip üzerinde bir örnek gerçekleştirmeye çalışacağım.

Öncelikle soket programlama nedir?

Socket-Workflow

Soketler için istemci (Client) ve sunucu (Server) arasındaki bağlantının sağlanması için olan bir iletişim kanalı diyebiliriz. Yaşam döngüsünü basitçe tarif etmek gerekirse, sunucu önceden belirlenen portu dinler, istemci ise bu porta mesaj gönderir.

İletişim protokolü olarak TCP de, sunucu belirli bir portu dinleyerek gelen istekleri karşılar, UDP protokolünde ise, tek bir soket üzerinden birden çok istemciye veriyi iletebilir.

Unutulmamalıdır ki UDP protokolünü kullanmaya karar vermiş biri, meydana gelebilecek paket kayıplarını da göze alıp, bunları iyi handle etmesi gerekmektedir.

Bunun en büyük örneği VOIP sistemlerinde ses paketlerinin zaman zaman kayıplara uğramasıdır. Kısaca “fire and forget” mantığında çalışmaktadır diyebiliriz.

Nerelerde kullanılıyor?

Bu makaleyi yazma sebebimden yola çıkarak, öncelikle gerçek bir senaryodan örnek vermek istiyorum.

Çalışıyor olduğum firmada, oldukça yoğun servis verileri ile çalışmaktayız. IIS’de konumlanan tek bir uygulama içerisinden, yaklaşık 30+ farklı servis üzerinden verilerin eş zamanlı olarak çekildiğini ve işlendiğini düşünebilirsiniz. Çekilen bu verilerin boyut’ları ise oldukça büyük bir durumda.

Domain içerisine her bir yeni servis eklendiğinde ise, IIS üzerindeki uygulama, iyice hantallaşmaya ve sunucuyu oldukça yormaya başlamıştı. Bu gibi sebeplerden yola çıkarak, ana uygulama domain’i içerisinden servis’leri ayırmaya karar verdik. Ayrılan bu servisleri ise, “n” adet yeni oluşturduğumuz servis makinelerine deployment işlemlerini gerçekleştirdik. Ana uygulamamız ile servis makineleri arasındaki iletişimi ise, gerek veri boyutlarının büyüklüğünden gerekse de daha hızlı bir iletişim sağlayabilmek için soket üzerinden yönetmeye karar verdik.

Böylece IIS üzerinde konumlanan ana uygulamamız üzerindeki yükü oldukça azaltmış ve daha esnek bir yapı sağlamış olduk.

Bir başka örnek vermek gerekirse, gerçek zamanlı uygulamaları düşünebiliriz. Örneğin chat veya bazı pos cihazlarını örnek olarak gösterebiliriz.

Bir örnek gerçekleştirelim

Öncelikle soket aracılığı ile aktarıcak olduğumuz nesnelerimizi, DataTransferObjects isminde bir proje içerisinde tanımlayalım. Öncelikle ExampleDTO class’ını aşağıdaki gibi oluşturalım.

using System;

namespace ExampleDataTransferObjects
{
    /// <summary>
    /// Serialize edebilmek için Serializable attributü ile işaretliyoruz.
    /// </summary>
    [Serializable]
    public class ExampleDTO
    {
        public string Status { get; set; }
        public string Message { get; set; }
    }
}

Oluşturduktan sonra kodlamaya sunucu ile devam edelim.

Solution içerisine yeni bir console application projesi ekleyip ExampleServer adını verelim. İçerisinde ise Sockets isminde bir klasör oluşturup, “Client” class’ını aşağıdaki gibi ekleyelim.

using ExampleDataTransferObjects;
using System;
using System.IO;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;

namespace ExampleServer.Sockets
{
    public delegate void OnExampleDTOReceived(ExampleDTO eDTO);

    public class Client
    {
        #region Variables
        public OnExampleDTOReceived _OnExampleDTOReceived;
        Socket _Socket;

        // Socket işlemleri sırasında oluşabilecek errorları bu enum ile handle edebiliriz.
        SocketError socketError;
        byte[] tempBuffer = new byte[1024]; // 1024 boyutunda temp bir buffer, gelen verinin boyutu kadarıyla bunu receive kısmında handle edeceğiz.
        #endregion

        #region Constructor
        public Client(Socket socket)
        {
            _Socket = socket;
        }
        #endregion

        #region Public Methods
        public void Start()
        {
            // Socket üzerinden data dinlemeye başlıyoruz.
            _Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
        }
        #endregion

        #region Private Methods
        void OnBeginReceiveCallback(IAsyncResult asyncResult)
        {
            // Almayı bitiriyoruz ve gelen byte array'in boyutunu vermektedir.
            int receivedDataLength = _Socket.EndReceive(asyncResult, out socketError);

            if (receivedDataLength <= 0 && socketError != SocketError.Success)
            {
                // Gelen byte array verisi boş ise bağlantı kopmuş demektir. Burayı istediğiniz gibi handle edebilirsiniz.
                return;
            }

            // Gelen byte array boyutunda yeni bir byte array oluşturuyoruz.
            byte[] resizedBuffer = new byte[receivedDataLength];

            Array.Copy(tempBuffer, 0, resizedBuffer, 0, resizedBuffer.Length);

            // Gelen datayı burada ele alacağız.
            HandleReceivedData(resizedBuffer);

            // Tekrardan socket üzerinden data dinlemeye başlıyoruz.
            // Start();

            // Socket üzerinden data dinlemeye başlıyoruz.
            _Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
        }

        /// <summary>
        /// Gelen datayı handle edeceğimiz nokta.
        /// </summary>
        /// <param name="resizedBuffer"></param>
        void HandleReceivedData(byte[] resizedBuffer)
        {
            if (_OnExampleDTOReceived != null)
            {
                using (var ms = new MemoryStream(resizedBuffer))
                {
                    // BinaryFormatter aracılığı ile object tipimize geri deserialize işlemi gerçekleştiriyoruz ve ilgili delegate'e parametre olarak geçiyoruz.
                    ExampleDTO exampleDTO = new BinaryFormatter().Deserialize(ms) as ExampleDTO;

                    _OnExampleDTOReceived(exampleDTO);
                }
            }
        }
        #endregion
    }
}

Sunucu için istemci işlemlerini gerçekleştireceğimiz sınıfı ekledikten sonra ise “Sockets” klasörü içerisine asıl dinleme işlemini yapacağımız class olan “Listener” class’ını ekleyelim ve aşağıdaki gibi kodlayalım.

using ExampleDataTransferObjects;
using System;
using System.Net;
using System.Net.Sockets;

namespace ExampleServer.Sockets
{
    public class Listener
    {
        #region Variables
        Socket _Socket;
        int _Port;
        int _MaxConnectionQueue;
        #endregion

        #region Constructor
        public Listener(int port, int maxConnectionQueue)
        {
            _Port = port;
            _MaxConnectionQueue = maxConnectionQueue;

            // Socket'i tanımlıyoruz IPv4, socket tipimiz stream olacak ve TCP Protokolü ile haberleşeceğiz. 
            // TCP Protokolünde server belirlenen portu dinler ve gelen istekleri karşılar oysaki UDP Protokolünde tek bir socket üzerinden birden çok client'a ulaşmak mümkündür.
            _Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }
        #endregion

        #region Public Methods
        public void Start()
        {
            IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, _Port);

            // Socket'e herhangi bir yerden ve belirttiğimiz porttan gelecek olan bağlantıları belirtmeliyiz.
            _Socket.Bind(ipEndPoint);

            // Socketten gelecek olan bağlantıları dinlemeye başlıyoruz ve maksimum dinleyeceği bağlantıyı belirtiyoruz.
            _Socket.Listen(_MaxConnectionQueue);

            // BeginAccept ile asenkron olarak gelen bağlantıları kabul ediyoruz.
            _Socket.BeginAccept(OnBeginAccept, _Socket);
        }
        #endregion

        #region Private Methods
        void OnBeginAccept(IAsyncResult asyncResult)
        {
            Socket socket = _Socket.EndAccept(asyncResult);
            Client client = new Client(socket);

            // Client tarafından gönderilen datamızı işleyeceğimiz kısım.
            client._OnExampleDTOReceived += new Sockets.OnExampleDTOReceived(OnExampleDTOReceived);
            client.Start();

            // Tekrardan dinlemeye devam diyoruz.
            _Socket.BeginAccept(OnBeginAccept, null);
        }

        void OnExampleDTOReceived(ExampleDTO exampleDTO)
        {
            // Client tarafından gelen data, istediğiniz gibi burada handle edebilirsiniz senaryonuza göre.
            Console.WriteLine(string.Format("Status: {0}", exampleDTO.Status));
            Console.WriteLine(string.Format("Message: {0}", exampleDTO.Message));
        }
        #endregion
    }
}

Dinleme işlemini yapacağımız Listener class’ını hazırladığımıza göre, şimdi console uygulamamızın “Program” class’ının Main method’u içerisinde dinleme işlemine başlayabiliriz.

using ExampleServer.Sockets;
using System;

namespace ExampleServer
{
    class Program
    {
        static void Main(string[] args)
        {
            int port = 5555;
            Console.WriteLine(string.Format("Server Başlatıldı. Port: {0}", port));
            Console.WriteLine("-----------------------------");

            Listener listener = new Listener(port, 50);

            listener.Start();

            Console.ReadLine();
        }
    }
}

Böylelikle 5555 port’u üzerinden gelecek olan bağlantıları dinleyip, işleyecek bir sunucuya sahip olduk. Şimdi istemciyi kodlamaya başlayabiliriz.

Solution üzerine ExampleClient isminde bir console application projesi ekleyelim. Ardından içerisinde Sockets isimli bir klasör oluşturup aşağıdaki gibi bu klasör içerisinde ExampleSocket isimli bir class tanımlayalım.

using ExampleDataTransferObjects;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Serialization.Formatters.Binary;

namespace ExampleClient.Sockets
{
    public class ExampleSocket
    {
        #region Variables
        Socket _Socket;
        IPEndPoint _IPEndPoint;

        // Socket işlemleri sırasında oluşabilecek errorları bu enum ile handle edebiliriz.
        SocketError socketError;
        byte[] tempBuffer = new byte[1024];
        #endregion

        #region Constructor
        public ExampleSocket(IPEndPoint ipEndPoint)
        {
            _IPEndPoint = ipEndPoint;

            // Socket'i tanımlıyoruz IPv4, socket tipimiz stream olacak ve TCP Protokolü ile haberleşeceğiz. 
            // TCP Protokolünde server belirlenen portu dinler ve gelen istekleri karşılar oysaki UDP Protokolünde tek bir socket üzerinden birden çok client'a ulaşmak mümkündür.
            _Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }
        #endregion

        #region Public Methods
        public void Start()
        {
            // BeginConnect ile asenkron olarak bir bağlantı başlatıyoruz.
            _Socket.BeginConnect(_IPEndPoint, OnBeginConnect, null);
        }

        public void SendData(ExampleDTO exampleDTO)
        {
            using (var ms = new MemoryStream())
            {
                // İlgili object'imizi binary'e serialize ediyoruz.
                new BinaryFormatter().Serialize(ms, exampleDTO);
                IList<ArraySegment<byte>> data = new List<ArraySegment<byte>>();

                data.Add(new ArraySegment<byte>(ms.ToArray()));

                // Gönderme işlemine başlıyoruz.
                _Socket.BeginSend(data, SocketFlags.None, out socketError, (asyncResult) =>
                {
                    // Gönderme işlemini bitiriyoruz.
                    int length = _Socket.EndSend(asyncResult, out socketError);

                    if (length <= 0 || socketError != SocketError.Success)
                    {
                        Console.WriteLine("Server bağlantısı koptu!");
                        return;
                    }
                }, null);

                if (socketError != SocketError.Success)
                    Console.WriteLine("Server bağlantısı koptu!");
            }
        }
        #endregion

        #region Private Methods
        void OnBeginConnect(IAsyncResult asyncResult)
        {
            try
            {
                // Bağlanma işlemini bitiriyoruz.
                _Socket.EndConnect(asyncResult);

                // Bağlandığımız socket üzerinden datayı dinlemeye başlıyoruz.
                _Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceive, null);
            }
            catch (SocketException)
            {
                // Servera bağlanamama durumlarında bize SocketException fırlatıcaktır. Hataları burada handle edebilirsiniz.
                Console.WriteLine("Servera bağlanılamıyor!");
            }
        }

        void OnBeginReceive(IAsyncResult asyncResult)
        {
            // Almayı bitiriyoruz ve geriye gelen byte array'in boyutunu vermektedir.
            int receivedDataLength = _Socket.EndReceive(asyncResult, out socketError);

            if (receivedDataLength <= 0 || socketError != SocketError.Success)
            {
                // Gelen byte array verisi boş ise bağlantı kopmuş demektir. Burayı istediğiniz gibi handle edebilirsiniz.
                Console.WriteLine("Server bağlantısı koptu!");
                return;
            }

            // Tekrardan socket üzerinden datayı dinlemeye başlıyoruz.
            _Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceive, null);
        }
        #endregion
    }
}

İstemcimiz için soketi hazırladığımıza göre, şimdi console uygulamamızın Program class’ının Main method’u içerisinde soket’e bağlanma işlemlerini gerçekleştirebiliriz.

using ExampleClient.Sockets;
using ExampleDataTransferObjects;
using System;
using System.Net;
using System.Linq;

namespace ExampleClient
{
    class Program
    {
        static void Main(string[] args)
        {
            int port = 5555;
            Console.WriteLine(string.Format("Client Başlatıldı. Port: {0}", port));
            Console.WriteLine("-----------------------------");

            ExampleSocket exampleSocket = new ExampleSocket(new IPEndPoint(IPAddress.Parse("127.0.0.1"), port));
            exampleSocket.Start();

            Console.WriteLine("Göndermek için \"G\", basınız...");

            int count = 1;
            while (Console.ReadLine().ToUpper() == "G")
            {
                ExampleDTO exampleDTO = new ExampleDTO()
                {
                    Status = string.Format("{0}. Alındı", count),
                    Message = string.Format("{0} ip numaralı client üzerinden geliyorum!", GetLocalIPAddress())
                };

                exampleSocket.SendData(exampleDTO);
                count++;
            }

            Console.ReadLine();
        }

        static string GetLocalIPAddress()
        {
            string localIP = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Where(a => a.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).FirstOrDefault().ToString();

            return localIP;
        }
    }
}

İstemcimizde sunucuya bağlanmak için hazır durumda.Tek yapmamız gereken göndermek için G tuşuna basmak.

socket-test

 

ExampleDataTransferObjects kütüphanesini istemci ve sunucu tarafında referans olarak eklemeyi unutmayınız.

Kaynak kodu ekte bulabilirsiniz.

SocketProgrammingExample

 

Kategori:.NET

29 Yorum

  1. halil ibrahim şeker halil ibrahim şeker

    Paylaşım için çok teşekkürler.

  2. atakan savaş atakan savaş

    Selamlar.
    Bu yapıyı kullanarak server ve client arasında büyük veriler göndermek problem yaşatır mı? ayrıca ağı dinleyen programlar için ne kadar güvenli bu yöntem?

    • Merhaba, limit olarak herhangi bir limit bulunmamakta sadece buffer’ın aşılmamasına dikkat etmeniz gerekmektedir. https://msdn.microsoft.com/en-us/library/ms145160.aspx adresindeki notlar’ın bulunduğu kısımda okuyabilirsiniz. “You must ensure that the size of your buffer does not exceed the maximum packet size of the underlying service provider.” Ayrıca arp poisoning’e gelince herhangi biri server ağınıza ulaşıp o ağ üzerinde sniff işlemi yaparsa elbette dinlenebilir. Buda sizin mimari olarak hatanızı göstermektedir.

  3. Hocam merhaba, online oyun için socket oluşturma çabası içerisindeyiz 🙂 Birde bunun multi-thread örneğini yayınlayabilir misiniz?

  4. ali ali

    maxsimum client sayısı nedir? belli bir sayıdan sonra saçmalar mı?

    • Merhaba, maksimum client sayısına ortalama bir şey söylemek yanlış olur. Concurrent olarak gerçekleştireceğiz işlemlere, bu uygulamayı host edecek olan server’ın kapasitesine ve aynı zamanda network’e bağlı olan bir durum söz konusudur. Bu tarz uygulamalarda daha ölçeklenebilir bir yapı elde edebilmek için, load balancing tarzı işlemler ile yük maliyetini farklı server’lara dağıtabilirsiniz.

      • burak burak

        Hocam client Yazdığınız sınıf server görevi yapıyor niçin clientimiz sever işlemi yapıp bağlantıları dinliyor

        • Evet yazdığımız proje namespace’inde de olduğu gibi Server. Listener haricinde Client isminde bir class oluşturmamın sebebi ise, Listener içerisinde, client işlemlerini gerçekleştirmek. Client tarafından gönderilen datayı, işleyecek olan sınıf gibi düşünebilirsiniz, temsili. İsimlendirmeye takılmayın, siz istediğiniz gibi kullanabilirsiniz. 🙂

  5. Tuncay GÜVEN Tuncay GÜVEN

    Merhaba,

    Uzun zamandır böyle bir proje arıyordum. Çok teşekkürler
    Şimdi 224 bilgisayar için uzaktan yönetilebilir bir program yazabilirim.

    Paylaşımlarını takip ediyor olucam Sağolasın

  6. Tuncay Güven Tuncay Güven

    Gökhan kardeşim selam,

    Anlattığın konu o kadar güzel olmuş ki inan uzun zamandır böyle bir örnek arıyordum.
    Senden bir ricam olacak server kısmını windows form olarak tasarlar sak nasıl yapmamız gerekiyor.
    Amaç 224 bilgisayarda ayrı ayrı server çalıştıracağım client makineden gelen komuta göre windows form içinde yapması gerekenleri yazacağım fakat form tarafını çözemedim. Örnek mail atabilir sen sevinirim teşekkürer
    Tuncay G.

  7. Ahmet Öztürk Ahmet Öztürk

    Merhaba Gökhan Abi,

    Anlatım çok güzel olmuş. 1 yıldır c# ile uğraşıyorum. bu projeyi windows olarak nasıl yapabilirim.
    Hocamız bir proje yapmamızı istedi bende havalı proje yapmak istiyorum Arduino ve c# ile uzaktan led kontrol uygulaması düşünüyorum. Labaratuvardaki iki bilgisayar arası soket ile bağlanıp bir bilgisayara bağlı olan arduino com üzerinden aldığı veriye göre led yakacak yada kapatacak. Arduino için bir abim yardımcı olacak.

    size simdiden teşekkürlerimi iletiyorum iyi çalışmalar

  8. Gökhan hocam, çok güzel bir konuya değinmişsiniz , emeğinize sağlık. Bir sorum olacak. Uygulama çok güzel ama Server üzerinden istediğim client a nasıl mesaj gönderebilirim. Ya da aynı anda bağlı client lara nasıl toplu mesaj gönderebilirim.

  9. Ömer Harmanşa Ömer Harmanşa

    Merhaba,
    Benim için faydalı bir paylaşım oldu. Bir sorum olacak. SendData metodunun geri dönüşü yok. SendData ile gönderdiğim veriyi sunucu tarafından işlendikten sonra geri almak istiyorum. Bunu nasıl yapabilirim?

  10. alex alex

    TSKKRLR

  11. murat murat

    Bunun form projesini paylaşmanız mümkün mü acaba ?

    • Merhaba, maalesef form projesi bulunmamakta. Fakat console kısmını kolayca bir form ile replace edebilirsiniz.

  12. MuratCanT MuratCanT

    Öncelikle elinize sağlık başarılı bir proje olmuş. Ben proje aracılığıyla TCP Sunucusuna veri göndermek istedim fakat program bana “System.Runtime.Serialization.SerializationException”, ” Ayrıştırma tamamlanmadan önce Akış Sonu ile karşılaşıldı” hatasını verdi. Bu hatayı neden almış olabilirim? Bir çözüm öneriniz var mı? Şimdiden teşekkürlerimi sunuyorum.

    • Merhaba, teşekkürler öncelikle. Uygulamada herhangi bir değişiklik yaptınız mı? Aldığınız hata, stream işlemi bitmeden, dispose’a uğramış gibi görünüyor.

  13. Sinan Sinan

    Hocam Selam,
    Elinize sağlık bir kaç sorum olacak.
    1. Bazen şöyle bir durum oluyor client bana data göndereceği zaman ilk datanın sonucuna bakmadan direk bir kaç milisaniye fark ile aynı datayı basıyor. Bunu server tarafında nasıl engelleyebilirim?
    1.a => Ben burada bir liste yapıp connect olan clientları nasıl tutabilirim?
    2. MaxConnection 2 verdiğim hale 7-8 adet client bağlandı bunu nasıl sabitleyebilirim?

    Teşekkürler.

  14. damla damla

    Merhaba,

    Kodu anlamak için epey çaba gerekiyor. İlk defa soket programlamayı öğrenecek kişiler için pek anlaşılır bir örnek olmamış . Yine de elinize sağlık. Daha kısa ve net yazılabilirdi.

  15. sezer sezer

    Merhaba Hocam,
    Bu kod ile Clientten servere mesaj göndermeyi yaptım fakat serverden cliente tekrar nasıl bilgi göndereceğiz ?

    • Merhaba, ExampleClient’ın OnBeginReceive method’unu genişletmeniz ve “SendData” method’unu, ExampleServer içerisine uyarlamanız gerekmektedir.

      • sezer sezer

        Hocam bu konuda çok yetkin değilim nasıl bir uyarlama ve genişletme yapabiliriz bu konuda yardımcı olursanız çok sevinirim. Kodunuzu alıp windows forma uyguladım sadece clientten servere mesaj iletimi başarılı şekilde çalıştı fakat bu sorun karşıma çıktı. serverden clientte nasıl mesaj göndereceğimi bir çok deneme yapmama rağmen yapamadım 🙁

        • sezer sezer

          Bir örnek kod ile yapabilirseniz çok sevinirim.

          • sezer sezer

            Server Tarafındaki Client : SendData:

            public delegate void OnExampleDTOReceived(ExampleDTO eDTO);

            public class Client
            {
            #region Variables
            public OnExampleDTOReceived _OnExampleDTOReceived;
            Socket _Socket;
            IPEndPoint _IPEndPoint;
            // Socket işlemleri sırasında oluşabilecek errorları bu enum ile handle edebiliriz.
            SocketError socketError;
            byte[] tempBuffer = new byte[1024]; // 1024 boyutunda temp bir buffer, gelen verinin boyutu kadarıyla bunu receive kısmında handle edeceğiz.
            #endregion

            #region Constructor
            public Client(Socket socket)
            {
            _Socket = socket;
            }
            #endregion
            public Client(IPEndPoint ipEndPoint)
            {
            _IPEndPoint = ipEndPoint;

            // Socket’i tanımlıyoruz IPv4, socket tipimiz stream olacak ve TCP Protokolü ile haberleşeceğiz.
            // TCP Protokolünde server belirlenen portu dinler ve gelen istekleri karşılar oysaki UDP Protokolünde tek bir socket üzerinden birden çok client’a ulaşmak mümkündür.
            _Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            }

            #region Public Methods
            public void Start()
            {
            // Socket üzerinden data dinlemeye başlıyoruz.
            _Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
            }
            #endregion

            public void Send()
            {
            // BeginConnect ile asenkron olarak bir bağlantı başlatıyoruz.
            _Socket.BeginConnect(_IPEndPoint, OnBeginConnect, null);
            }

            void OnBeginConnect(IAsyncResult asyncResult)
            {
            try
            {
            // Bağlanma işlemini bitiriyoruz.
            _Socket.EndConnect(asyncResult);

            // Bağlandığımız socket üzerinden datayı dinlemeye başlıyoruz.
            _Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
            }
            catch (SocketException)
            {
            // Servera bağlanamama durumlarında bize SocketException fırlatıcaktır. Hataları burada handle edebilirsiniz.

            }
            }

            #region Private Methods
            void OnBeginReceiveCallback(IAsyncResult asyncResult)
            {
            // Almayı bitiriyoruz ve gelen byte array’in boyutunu vermektedir.
            int receivedDataLength = _Socket.EndReceive(asyncResult, out socketError);

            if (receivedDataLength <= 0 && socketError != SocketError.Success)
            {
            // Gelen byte array verisi boş ise bağlantı kopmuş demektir. Burayı istediğiniz gibi handle edebilirsiniz.
            return;
            }

            // Gelen byte array boyutunda yeni bir byte array oluşturuyoruz.
            byte[] resizedBuffer = new byte[receivedDataLength];

            Array.Copy(tempBuffer, 0, resizedBuffer, 0, resizedBuffer.Length);

            // Gelen datayı burada ele alacağız.
            HandleReceivedData(resizedBuffer);

            // Tekrardan socket üzerinden data dinlemeye başlıyoruz.
            // Start();

            // Socket üzerinden data dinlemeye başlıyoruz.
            _Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceiveCallback, null);
            }

            ///
            /// Gelen datayı handle edeceğimiz nokta.
            ///
            ///
            void HandleReceivedData(byte[] resizedBuffer)
            {
            if (_OnExampleDTOReceived != null)
            {
            using (var ms = new MemoryStream(resizedBuffer))
            {
            // BinaryFormatter aracılığı ile object tipimize geri deserialize işlemi gerçekleştiriyoruz ve ilgili delegate’e parametre olarak geçiyoruz.
            ExampleDTO exampleDTO = new BinaryFormatter().Deserialize(ms) as ExampleDTO;

            _OnExampleDTOReceived(exampleDTO);
            }
            }
            }

            public void SendData(ExampleDTO exampleDTO)
            {
            using (var ms = new MemoryStream())
            {
            // İlgili object’imizi binary’e serialize ediyoruz.
            new BinaryFormatter().Serialize(ms, exampleDTO);
            IList<ArraySegment> data = new List<ArraySegment>();

            data.Add(new ArraySegment(ms.ToArray()));

            // Gönderme işlemine başlıyoruz.
            _Socket.BeginSend(data, SocketFlags.None, out socketError, (asyncResult) =>
            {
            // Gönderme işlemini bitiriyoruz.
            int length = _Socket.EndSend(asyncResult, out socketError);

            if (length <= 0 || socketError != SocketError.Success)
            {

            return;
            }
            }, null);

            }
            }
            #endregion
            }

            Client Tarafı Receive :

            public delegate void OnExampleDTOReceived(ExampleDTO eDTO);

            public class Client
            {
            #region Variables
            public OnExampleDTOReceived _OnExampleDTOReceived;
            Socket _Socket;
            IPEndPoint _IPEndPoint;
            SimpleTracer log = new SimpleTracer();

            // Socket işlemleri sırasında oluşabilecek errorları bu enum ile handle edebiliriz.
            SocketError socketError;
            byte[] tempBuffer = new byte[1024];
            #endregion

            #region Constructor
            public Client(IPEndPoint ipEndPoint)
            {
            _IPEndPoint = ipEndPoint;

            // Socket'i tanımlıyoruz IPv4, socket tipimiz stream olacak ve TCP Protokolü ile haberleşeceğiz.
            // TCP Protokolünde server belirlenen portu dinler ve gelen istekleri karşılar oysaki UDP Protokolünde tek bir socket üzerinden birden çok client'a ulaşmak mümkündür.
            _Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            }
            #endregion

            public Client(Socket socket)
            {
            _Socket = socket;
            }

            #region Public Methods
            public void Start()
            {
            // BeginConnect ile asenkron olarak bir bağlantı başlatıyoruz.
            _Socket.BeginConnect(_IPEndPoint, OnBeginConnect, null);
            }

            public void Receive()
            {
            // Socket üzerinden data dinlemeye başlıyoruz.
            _Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceive, null);
            }

            //public string Receive()
            //{
            // // Socket üzerinden data dinlemeye başlıyoruz.
            // //_Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceive, null);

            // // int bytes= _Socket.Receive(tempBuffer);

            // //string str= Encoding.ASCII.GetString(tempBuffer,0,bytes);

            // return str;
            //}

            public void SendData(ExampleDTO exampleDTO)
            {
            using (var ms = new MemoryStream())
            {
            // İlgili object'imizi binary'e serialize ediyoruz.
            new BinaryFormatter().Serialize(ms, exampleDTO);
            IList<ArraySegment> data = new List<ArraySegment>();

            data.Add(new ArraySegment(ms.ToArray()));

            // Gönderme işlemine başlıyoruz.
            _Socket.BeginSend(data, SocketFlags.None, out socketError, (asyncResult) =>
            {
            // Gönderme işlemini bitiriyoruz.
            int length = _Socket.EndSend(asyncResult, out socketError);

            if (length <= 0 || socketError != SocketError.Success)
            {
            log.append("Server bağlantısı koptu!","");
            return;
            }
            }, null);

            if (socketError != SocketError.Success)
            log.append("Server bağlantısı koptu!","");
            }
            }
            #endregion

            #region Private Methods
            void OnBeginConnect(IAsyncResult asyncResult)
            {
            try
            {
            // Bağlanma işlemini bitiriyoruz.
            _Socket.EndConnect(asyncResult);

            // Bağlandığımız socket üzerinden datayı dinlemeye başlıyoruz.
            _Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceive, null);
            }
            catch (SocketException)
            {
            // Servera bağlanamama durumlarında bize SocketException fırlatıcaktır. Hataları burada handle edebilirsiniz.
            log.append("Servera bağlanılamıyor!","");
            }
            }

            void OnBeginAccept(IAsyncResult asyncResult)
            {
            Socket socket = _Socket.EndAccept(asyncResult);

            // Tekrardan dinlemeye devam diyoruz.
            _Socket.BeginAccept(OnBeginAccept, null);
            }

            void OnBeginReceive(IAsyncResult asyncResult)
            {
            // Almayı bitiriyoruz ve geriye gelen byte array'in boyutunu vermektedir.
            int receivedDataLength = _Socket.EndReceive(asyncResult, out socketError);

            if (receivedDataLength <= 0 || socketError != SocketError.Success)
            {
            // Gelen byte array verisi boş ise bağlantı kopmuş demektir. Burayı istediğiniz gibi handle edebilirsiniz.
            log.append("Server bağlantısı koptu!","");
            return;
            }

            // Gelen byte array boyutunda yeni bir byte array oluşturuyoruz.
            byte[] resizedBuffer = new byte[receivedDataLength];

            Array.Copy(tempBuffer, 0, resizedBuffer, 0, resizedBuffer.Length);

            // Gelen datayı burada ele alacağız.
            HandleReceivedData(resizedBuffer);

            // Tekrardan socket üzerinden datayı dinlemeye başlıyoruz.
            _Socket.BeginReceive(tempBuffer, 0, tempBuffer.Length, SocketFlags.None, OnBeginReceive, null);
            }

            ///
            /// Gelen datayı handle edeceğimiz nokta.
            ///
            ///
            void HandleReceivedData(byte[] resizedBuffer)
            {
            if (_OnExampleDTOReceived != null)
            {
            using (var ms = new MemoryStream(resizedBuffer))
            {
            // BinaryFormatter aracılığı ile object tipimize geri deserialize işlemi gerçekleştiriyoruz ve ilgili delegate’e parametre olarak geçiyoruz.
            ExampleDTO exampleDTO = new BinaryFormatter().Deserialize(ms) as ExampleDTO;

            // Client tarafından gelen data, istediğiniz gibi burada handle edebilirsiniz senaryonuza göre.

            _OnExampleDTOReceived(exampleDTO);
            }
            }
            }

            #endregion
            }

            Bu şekilde bişeyler yaptım ama çalışmadı 🙁

        • Selam son dönemlerde yoğun olduğum için vakit bulamadım. Bu hafta içerisinde bir örnek göndermeye çalışacağım.

          • sezer sezer

            Gökhan Bey,
            Sorunu şu şekilde çözdüm server tarafında cliente şunu ekledim :

            void HandleReceivedData(byte[] resizedBuffer)
            {
            try
            {
            if (_OnExampleDTOReceived != null)
            {
            //using (var ms = new MemoryStream(resizedBuffer))
            //{
            // // BinaryFormatter aracılığı ile object tipimize geri deserialize işlemi gerçekleştiriyoruz ve ilgili delegate’e parametre olarak geçiyoruz.
            // string exampleDTO = new BinaryFormatter().Deserialize(ms) as string;

            // if (exampleDTO == “POSALIVE”)
            // SendData(“ACK”);

            // _OnExampleDTOReceived(exampleDTO);
            //}

            using (MemoryStream stream = new MemoryStream(resizedBuffer))
            {
            stream.Position = 0;
            var sr = new StreamReader(stream);
            string myStr = sr.ReadToEnd();

            if (myStr.Contains(“POSALIVE”))
            {
            SendData(“ACK”);
            flag = “Y”;

            }
            _OnExampleDTOReceived(myStr);
            }
            }
            }catch(Exception ex)
            {
            string logstr = ex.InnerException == null ? “” : ex.InnerException.Message;
            log.append(“ERROR:” + ex.Message + “–>” + logstr, logdirectory);
            MessageBox.Show(ex.Message);
            Environment.Exit(0);
            }
            }

            public void SendData(string message)
            {
            try
            {
            using (var ms = new MemoryStream())
            {
            // İlgili object’imizi binary’e serialize ediyoruz.
            new BinaryFormatter().Serialize(ms, message);
            IList<ArraySegment> data = new List<ArraySegment>();

            data.Add(new ArraySegment(ms.ToArray()));

            // Gönderme işlemine başlıyoruz.
            _Socket.BeginSend(data, SocketFlags.None, out socketError, (asyncResult) =>
            {
            // Gönderme işlemini bitiriyoruz.
            int length = _Socket.EndSend(asyncResult, out socketError);

            if (length ” + logstr, logdirectory);
            MessageBox.Show(ex.Message);
            Environment.Exit(0);
            }
            }
            İlginiz için teşekkür ederim

          • Teşekkür ederim katkınız için. Diğer ihtiyacı olan arkadaşlara da kesinlikle faydası olacaktır.

  16. Fatih Fatih

    Merhaba,

    2 tane farklı portu aynı anda okumak istiyorum.
    bunun için 2 tane socket tanımladım. Socketleri farklı
    threadlerde çalıştırınca sıkıntısız olmuyor. Ama tek thread içine
    yazınca bu sefer birbirlerini bloklamaya başlıyolar. Bu özelliklerini
    nasıl kapatabilirim bir fikriniz var mı? Teşekkürler…

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Bu site, istenmeyenleri azaltmak için Akismet kullanıyor. Yorum verilerinizin nasıl işlendiği hakkında daha fazla bilgi edinin.