Search code examples
c#socketsasyncsocket

How to solve C# Asynchronous Socket Programming Client/Server problem?


I found one article for this program . (https://www.gokhan-gokalp.com/en/c-ile-asenkron-socket-programlama/)

But I have problem it is not sending information Server to Client. I have to write receive method in client side and I have to right send method in server side. They are missing. How can I implement ?

Client Side : Main program

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;
        }
    }
}

Client.cs: This client will pass data to server.

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
    }
}

ExampleDataTransferObjects.dll: this dll will transfer data client to server

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; }
    }
}

Server Side:

Client.cs: It will receive data and send to listener

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
    }
}

Listener: it will listen data async

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
    }
}

Server Main Program:

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();
        }
    }
}

Solution

  • I solved problem in client.cs with this code :

     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.
                    //    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");
                        _OnExampleDTOReceived(myStr);
                    }
                }
            }
    
            public void SendData(string message)
            {
                using (var ms = new MemoryStream())
                {
                    // İlgili object'imizi binary'e serialize ediyoruz.
                    new BinaryFormatter().Serialize(ms, message);
                    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)
                        {
                            log.append("Server bağlantısı koptu!", "");
                            return;
                        }
                    }, null);
    
                    if (socketError != SocketError.Success)
                        log.append("Server bağlantısı koptu!", "");
                }
            }
    

    I added sent data method in client.cs