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

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

黄舟
黄舟원래의
2017-02-27 11:22:261592검색

이 기사에서는

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


이 섹션에서는 소켓을 사용하여 동기식 UDP 서버를 구현하는 방법을 소개합니다.

소켓 동기화 UDP 서버


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

클라이언트 상태 캡슐화 클래스

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


서버 이벤트 매개변수 클래스

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

위 내용은 C# 네트워크 프로그래밍 시리즈 기사(6)의 UDP 서버 동기화를 위한 소켓 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!


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