Maison  >  Article  >  développement back-end  >  Articles de la série de programmation réseau C# (6) Socket implémente un serveur UDP synchrone

Articles de la série de programmation réseau C# (6) Socket implémente un serveur UDP synchrone

黄舟
黄舟original
2017-02-27 11:22:261585parcourir

Cet article présente

Dans .Net, l'espace de noms System.Net.Sockets fournit une implémentation gérée de l'interface Windows Sockets (Winsock) pour les développeurs qui doivent contrôler étroitement l'accès au réseau. Toutes les autres classes d'accès réseau de l'espace de noms System.Net sont construites sur cette implémentation de socket. Les classes TCPClient, TCPListener et UDPClient encapsulent des informations détaillées sur la création de connexions TCP et UDP à Internet. La classe NetworkStream fournit le flux de données de base du réseau ; accès, Socket peut être vu dans de nombreux services Internet courants, tels que Telnet, HTTP, Email, Echo, etc. Bien que ces services aient des définitions différentes des protocoles de communication, leur transmission de base utilise Socket. En fait, Socket peut être considéré comme un canal de données comme un Stream. Ce canal s'établit entre l'application (client) et le serveur distant. Ensuite, la lecture (réception) et l'écriture (envoi) des données se font toutes deux via ce canal. .
On peut voir qu'après avoir créé un objet Socket côté application ou côté serveur, vous pouvez utiliser la méthode Send/SentTo pour envoyer des données au Socket connecté, ou utiliser la méthode Receiver/ReceiveFrom pour recevoir des données du Socket connecté. Socket ;
Pour la programmation Socket, la classe Socket du .NET Framework est une version de code géré du service socket fourni par l'API Winsock32. Il existe un certain nombre de méthodes fournies pour implémenter la programmation réseau et, dans la plupart des cas, les méthodes de la classe Socket rassemblent simplement les données vers leurs copies Win32 natives et gèrent tous les contrôles de sécurité nécessaires. Si vous êtes familier avec les fonctions de l'API Winsock, il sera très simple d'utiliser la classe Socket pour écrire des programmes réseau. Bien sûr, si vous n'y avez jamais été exposé, ce ne sera pas trop difficile. constatez que l'utilisation de la classe Socket pour développer des applications réseau Windows comporte en réalité des règles à trouver, et elles suivent à peu près les mêmes étapes dans la plupart des cas.


Cette section présente l'utilisation de Socket pour implémenter un serveur UDP synchrone.

Serveur UDP de synchronisation de socket


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace NetFrame.Net.UDP.Sock.Synchronous
{
    /// <summary>
    /// Socket 实现同步UDP服务器
    /// </summary>
    public class SocketUDPServer
    {
        #region Fields
        /// <summary>
        /// 服务器程序允许的最大客户端连接数
        /// </summary>
        private int _maxClient;

        /// <summary>
        /// 当前的连接的客户端数
        /// </summary>
        private int _clientCount;

        /// <summary>
        /// 服务器使用的同步socket
        /// </summary>
        private Socket _serverSock;

        /// <summary>
        /// 客户端会话列表
        /// </summary>
        private List<SocketUDPState> _clients;

        private bool disposed = false;

        /// <summary>
        /// 数据接受缓冲区
        /// </summary>
        private byte[] _recvBuffer;

        #endregion

        #region Properties

        /// <summary>
        /// 服务器是否正在运行
        /// </summary>
        public bool IsRunning { get; private set; }
        /// <summary>
        /// 监听的IP地址
        /// </summary>
        public IPAddress Address { get; private set; }
        /// <summary>
        /// 监听的端口
        /// </summary>
        public int Port { get; private set; }
        /// <summary>
        /// 通信使用的编码
        /// </summary>
        public Encoding Encoding { get; set; }

        #endregion

        #region 构造函数

        /// <summary>
        /// 异步Socket UDP服务器
        /// </summary>
        /// <param name="listenPort">监听的端口</param>
        public SocketUDPServer(int listenPort)
            : this(IPAddress.Any, listenPort,1024)
        {
        }

        /// <summary>
        /// 异步Socket UDP服务器
        /// </summary>
        /// <param name="localEP">监听的终结点</param>
        public SocketUDPServer(IPEndPoint localEP)
            : this(localEP.Address, localEP.Port,1024)
        {
        }

        /// <summary>
        /// 异步Socket UDP服务器
        /// </summary>
        /// <param name="localIPAddress">监听的IP地址</param>
        /// <param name="listenPort">监听的端口</param>
        /// <param name="maxClient">最大客户端数量</param>
        public SocketUDPServer(IPAddress localIPAddress, int listenPort, int maxClient)
        {
            this.Address = localIPAddress;
            this.Port = listenPort;
            this.Encoding = Encoding.Default;

            _maxClient = maxClient;
            _clients = new List<SocketUDPState>();
            _serverSock = new Socket(localIPAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);

            _recvBuffer=new byte[_serverSock.ReceiveBufferSize];
        }

        #endregion

        #region Method
        /// <summary>
        /// 启动服务器
        /// </summary>
        /// <returns>异步TCP服务器</returns>
        public void Start()
        {
            if (!IsRunning)
            {
                IsRunning = true;
                _serverSock.Bind(new IPEndPoint(this.Address, this.Port));
                //启动一个线程监听数据
                new Thread(ReceiveData).Start();
            }
        }

        /// <summary>
        /// 停止服务器
        /// </summary>
        public void Stop()
        {
            if (IsRunning)
            {
                IsRunning = false;
                _serverSock.Close();
                //TODO 关闭对所有客户端的连接
                CloseAllClient();
            }
        }

        /// <summary>
        /// 同步数据接收方法
        /// </summary>
        private void ReceiveData()
        {
            int len = -1;
            EndPoint remote = null;
            while (true)
            {
                try
                {
                    len = _serverSock.ReceiveFrom(_recvBuffer, ref remote);

                    //if (!_clients.Contains(remote))
                    //{
                    //    _clients.Add(remote);
                    //}
                }
                catch (Exception)
                {
                    //TODO 异常处理操作
                    RaiseOtherException(null);
                }
            }
        }
        /// <summary>
        /// 同步发送数据
        /// </summary>
        public void Send(string msg, EndPoint clientip)
        {
            byte[] data = Encoding.Default.GetBytes(msg);
            try
            {
                _serverSock.SendTo(data, clientip);
                //数据发送完成事件
                RaiseCompletedSend(null);
            }
            catch (Exception)
            {
                //TODO 异常处理
                RaiseOtherException(null);
            }
        }

        #endregion

        #region 事件
        /// <summary>
        /// 接收到数据事件
        /// </summary>
        public event EventHandler<SocketUDPEventArgs> DataReceived;

        private void RaiseDataReceived(SocketUDPState state)
        {
            if (DataReceived != null)
            {
                DataReceived(this, new SocketUDPEventArgs(state));
            }
        }

        /// <summary>
        /// 数据发送完毕事件
        /// </summary>
        public event EventHandler<SocketUDPEventArgs> CompletedSend;

        /// <summary>
        /// 触发数据发送完毕的事件
        /// </summary>
        /// <param name="state"></param>
        private void RaiseCompletedSend(SocketUDPState state)
        {
            if (CompletedSend != null)
            {
                CompletedSend(this, new SocketUDPEventArgs(state));
            }
        }

        /// <summary>
        /// 网络错误事件
        /// </summary>
        public event EventHandler<SocketUDPEventArgs> NetError;
        /// <summary>
        /// 触发网络错误事件
        /// </summary>
        /// <param name="state"></param>
        private void RaiseNetError(SocketUDPState state)
        {
            if (NetError != null)
            {
                NetError(this, new SocketUDPEventArgs(state));
            }
        }

        /// <summary>
        /// 异常事件
        /// </summary>
        public event EventHandler<SocketUDPEventArgs> OtherException;
        /// <summary>
        /// 触发异常事件
        /// </summary>
        /// <param name="state"></param>
        private void RaiseOtherException(SocketUDPState state, string descrip)
        {
            if (OtherException != null)
            {
                OtherException(this, new SocketUDPEventArgs(descrip, state));
            }
        }
        private void RaiseOtherException(SocketUDPState state)
        {
            RaiseOtherException(state, "");
        }
        #endregion

        #region Close
        /// <summary>
        /// 关闭一个与客户端之间的会话
        /// </summary>
        /// <param name="state">需要关闭的客户端会话对象</param>
        public void Close(SocketUDPState state)
        {
            if (state != null)
            {
                _clients.Remove(state);
                _clientCount--;
                //TODO 触发关闭事件
            }
        }
        /// <summary>
        /// 关闭所有的客户端会话,与所有的客户端连接会断开
        /// </summary>
        public void CloseAllClient()
        {
            foreach (SocketUDPState client in _clients)
            {
                Close(client);
            }
            _clientCount = 0;
            _clients.Clear();
        }
        #endregion

        #region 释放
        /// <summary>
        /// Performs application-defined tasks associated with freeing, 
        /// releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release 
        /// both managed and unmanaged resources; <c>false</c> 
        /// to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    try
                    {
                        Stop();
                        if (_serverSock != null)
                        {
                            _serverSock = null;
                        }
                    }
                    catch (SocketException)
                    {
                        //TODO
                        RaiseOtherException(null);
                    }
                }
                disposed = true;
            }
        }
        #endregion
    }
}

Classe d'encapsulation de l'état du client

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;

namespace NetFrame.Net.UDP.Sock.Synchronous
{
    public class SocketUDPState
    {
        // Client   socket.
        public Socket workSocket = null;
        // Size of receive buffer.
        public const int BufferSize = 1024;
        // Receive buffer.
        public byte[] buffer = new byte[BufferSize];
        // Received data string.
        public StringBuilder sb = new StringBuilder();

        public EndPoint remote = new IPEndPoint(IPAddress.Any, 0);
    }
}


Classe de paramètres d'événement du serveur

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace NetFrame.Net.UDP.Sock.Synchronous
{
    /// <summary>
    /// Socket实现同步UDP服务器
    /// </summary>
    public class SocketUDPEventArgs:EventArgs
    {
        /// <summary>
        /// 提示信息
        /// </summary>
        public string _msg;

        /// <summary>
        /// 客户端状态封装类
        /// </summary>
        public SocketUDPState _state;

        /// <summary>
        /// 是否已经处理过了
        /// </summary>
        public bool IsHandled { get; set; }

        public SocketUDPEventArgs(string msg)
        {
            this._msg = msg;
            IsHandled = false;
        }
        public SocketUDPEventArgs(SocketUDPState state)
        {
            this._state = state;
            IsHandled = false;
        }
        public SocketUDPEventArgs(string msg, SocketUDPState state)
        {
            this._msg = msg;
            this._state = state;
            IsHandled = false;
        }
    }
}

Ce qui précède est le contenu de Socket pour synchroniser le serveur UDP dans l'article de la série de programmation réseau C# (6). Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois (www.php.cn) !


Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn