>  기사  >  백엔드 개발  >  C# 네트워크 프로그래밍 기사 시리즈(5) 소켓은 비동기 UDP 서버를 구현합니다.

C# 네트워크 프로그래밍 기사 시리즈(5) 소켓은 비동기 UDP 서버를 구현합니다.

黄舟
黄舟원래의
2017-02-27 11:21:012207검색

이 기사에서는

.Net에서 System.Net.Sockets 네임스페이스는 네트워크 액세스를 엄격하게 제어해야 하는 개발자를 위해 Windows 소켓(Winsock) 인터페이스의 관리형 구현을 제공합니다. System.Net 네임스페이스의 다른 모든 네트워크 액세스 클래스는 이 소켓 구현을 기반으로 구축되었습니다. TCPClient, TCPListener 및 UDPClient 클래스는 인터넷에 대한 TCP 및 UDP 연결 생성에 대한 자세한 정보를 캡슐화합니다. NetworkStream 클래스는 네트워크의 기본 데이터 흐름을 제공합니다. 액세스, 소켓은 텔넷, HTTP, 이메일, 에코 등과 같은 많은 일반적인 인터넷 서비스에서 볼 수 있습니다. 이러한 서비스는 통신 프로토콜에 대해 서로 다른 정의를 가지고 있지만 기본 전송은 소켓을 사용합니다. 실제로 소켓은 스트림과 같은 데이터 채널로 간주할 수 있습니다. 이 채널은 애플리케이션(클라이언트)과 원격 서버 사이에 설정되며 이 채널을 통해 데이터 읽기(수신)와 쓰기(전송)가 모두 수행됩니다. .
애플리케이션 측이나 서버 측에서 Socket 객체를 생성한 후 Send/SentTo 메소드를 사용하여 연결된 Socket으로 데이터를 보내거나, Receiver/ReceiveFrom 메소드를 사용할 수 있음을 알 수 있다. 연결된 소켓에서 데이터를 수신합니다.
소켓 프로그래밍의 경우 .NET Framework의 소켓 클래스는 Winsock32 API에서 제공하는 소켓 서비스의 관리 코드 버전입니다. 네트워크 프로그래밍을 구현하기 위해 제공되는 여러 메서드가 있으며 대부분의 경우 Socket 클래스 메서드는 단순히 데이터를 기본 Win32 복사본으로 마샬링하고 필요한 보안 검사를 처리합니다. Winsock API 함수에 익숙하다면 Socket 클래스를 사용하여 네트워크 프로그램을 작성하는 것이 매우 쉬울 것입니다. 물론, 한 번도 사용해 본 적이 없다면 아래 설명을 따르면 그리 어렵지 않을 것입니다. 창을 개발하기 위해 Socket 클래스를 사용하는 것을 발견 웹 애플리케이션에는 규칙이 있으며 대부분의 경우 거의 동일한 단계를 따릅니다.


이 섹션에서는 소켓을 사용하여 고성능 비동기 UDP 서버를 구현하는 방법을 소개합니다. 실제로 UDP는 클라이언트를 구분하지 않습니다. 및 server.이지만 때로는 UDP를 사용하여 서버와 통신합니다.

소켓 비동기 UDP 서버

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

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

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

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

        /// <summary>
        /// 客户端会话列表
        /// </summary>
        //private List<AsyncUDPSocketState> _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 AsyncSocketUDPServer(int listenPort)
            : this(IPAddress.Any, listenPort,1024)
        {
        }

        /// <summary>
        /// 异步Socket UDP服务器
        /// </summary>
        /// <param name="localEP">监听的终结点</param>
        public AsyncSocketUDPServer(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 AsyncSocketUDPServer(IPAddress localIPAddress, int listenPort, int maxClient)
        {
            this.Address = localIPAddress;
            this.Port = listenPort;
            this.Encoding = Encoding.Default;

            _maxClient = maxClient;
            //_clients = new List<AsyncUDPSocketState>();
            _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));
                //_serverSock.Connect(new IPEndPoint(IPAddress.Any, 0));

                AsyncSocketUDPState so = new AsyncSocketUDPState();
                so.workSocket = _serverSock;

                _serverSock.BeginReceiveFrom(so.buffer, 0, so.buffer.Length, SocketFlags.None,
                    ref so.remote, new AsyncCallback(ReceiveDataAsync), null);


                //EndPoint sender = new IPEndPoint(IPAddress.Any, 0);

                //_serverSock.BeginReceiveFrom(_recvBuffer, 0, _recvBuffer.Length, SocketFlags.None,
                //    ref sender, new AsyncCallback(ReceiveDataAsync), sender);

                //BeginReceive 和 BeginReceiveFrom的区别是什么
                /*_serverSock.BeginReceive(_recvBuffer, 0, _recvBuffer.Length, SocketFlags.None,
                    new AsyncCallback(ReceiveDataAsync), null);*/
            }
        }

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

            }
        }

        /// <summary>
        /// 接收数据的方法
        /// </summary>
        /// <param name="ar"></param>
        private void ReceiveDataAsync(IAsyncResult ar)
        {
            AsyncSocketUDPState so = ar.AsyncState as AsyncSocketUDPState;
            //EndPoint sender = new IPEndPoint(IPAddress.Any, 0);
            int len = -1;
            try
            {
                len = _serverSock.EndReceiveFrom(ar, ref so.remote);

                //len = _serverSock.EndReceiveFrom(ar, ref sender);

                //EndReceiveFrom 和 EndReceive区别
                //len = _serverSock.EndReceive(ar);
                //TODO 处理数据

                //触发数据收到事件
                RaiseDataReceived(so);
            }
            catch (Exception)
            {
                //TODO 处理异常
                RaiseOtherException(so);
            }
            finally
            {
                if (IsRunning && _serverSock != null)
                    _serverSock.BeginReceiveFrom(so.buffer, 0, so.buffer.Length, SocketFlags.None,
                ref so.remote, new AsyncCallback(ReceiveDataAsync), so);
            }
        }
        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="remote"></param>
        public void Send(string msg,EndPoint remote)
        {
            byte[] data = Encoding.Default.GetBytes(msg);
            try
            {
                RaisePrepareSend(null);
                _serverSock.BeginSendTo(data, 0, data.Length, SocketFlags.None, remote, new AsyncCallback(SendDataEnd), _serverSock);
            }
            catch (Exception)
            {
                //TODO 异常处理
                RaiseOtherException(null);
            }
        }

        private void SendDataEnd(IAsyncResult ar)
        {
            ((Socket)ar.AsyncState).EndSendTo(ar);
            RaiseCompletedSend(null);
        }

        #endregion

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

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

        /// <summary>
        /// 发送数据前的事件
        /// </summary>
        public event EventHandler<AsyncSocketUDPEventArgs> PrepareSend;

        /// <summary>
        /// 触发发送数据前的事件
        /// </summary>
        /// <param name="state"></param>
        private void RaisePrepareSend(AsyncSocketUDPState state)
        {
            if (PrepareSend != null)
            {
                PrepareSend(this, new AsyncSocketUDPEventArgs(state));
            }
        }

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

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

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

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

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


세션 캡슐화 클래스

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

namespace NetFrame.Net.UDP.Sock.Asynchronous
{
    public class AsyncSocketUDPState
    {
        // 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);
    }
}

소켓 비동기 UDP 서버 이벤트 매개변수 클래스

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

namespace NetFrame.Net.UDP.Sock.Asynchronous
{
    /// <summary>
    /// SOCKET 异步UDP 事件类
    /// </summary>
    public class AsyncSocketUDPEventArgs : EventArgs
    {
        /// <summary>
        /// 提示信息
        /// </summary>
        public string _msg;

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

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

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

위는 C# 네트워크입니다. 프로그래밍 시리즈 기사 (5) 소켓은 비동기 UDP 서버의 내용을 구현합니다. 더 많은 관련 내용을 보려면 PHP 중국어 웹사이트(www.php.cn)를 참고하세요!



성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.