Jadual Kandungan
本文介绍
TcpListener同步TCP服务器
Rumah pembangunan bahagian belakang Tutorial C#.Net C#网络编程系列文章(四)之TcpListener实现同步TCP服务器

C#网络编程系列文章(四)之TcpListener实现同步TCP服务器

Feb 27, 2017 am 11:19 AM

本文介绍

TcpListener 类提供一些简单方法,用于在阻止同步模式下侦听和接受传入连接请求。 可使用 TcpClient 或 Socket 来连接 TcpListener。 可使用 IPEndPoint、本地 IP 地址及端口号或者仅使用端口号,来创建 TcpListener。 可以将本地 IP 地址指定为 Any,将本地端口号指定为 0(如果希望基础服务提供程序为您分配这些值)。 如果您选择这样做,可在连接套接字后使用 LocalEndpoint 属性来标识已指定的信息。使用 Start 方法,可开始侦听传入的连接请求。 Start 将对传入连接进行排队,直至您调用 Stop 方法或它已经完成 MaxConnections 排队为止。 可使用 AcceptSocket 或 AcceptTcpClient 从传入连接请求队列提取连接。 这两种方法将阻止。 如果要避免阻止,可首先使用 Pending 方法来确定队列中是否有可用的连接请求。
虽然TcpListener已经封装的比较不错了,我们于是就使用它在构造一个比较不错的同步TCP服务器,这里依然和前两章一样,给出服务器中的代码,代码中注释很详细,我也会给出相关的封装类。

TcpListener同步TCP服务器

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.TCP.Listener.Synchronous
{
    /// <summary>
    /// TcpListener实现同步TCP服务器
    /// </summary>
    public class TCPServer
    {
        #region Fields
        /// <summary>
        /// 服务器程序允许的最大客户端连接数
        /// </summary>
        private int _maxClient;

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

        /// <summary>
        /// 服务器使用的异步TcpListener
        /// </summary>
        private TcpListener _listener;

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

        private bool disposed = false;

        #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>
        /// 同步TCP服务器
        /// </summary>
        /// <param name="listenPort">监听的端口</param>
        public TCPServer(int listenPort)
            : this(IPAddress.Any, listenPort, 1024)
        {
        }

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

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

            _maxClient = maxClient;
            _clients = new List<TCPClientHandle>();
            _listener = new TcpListener(new IPEndPoint(this.Address, this.Port));
        }

        #endregion

        #region Method
        /// <summary>
        /// 启动服务器
        /// </summary>
        public void Start()
        {
            if (!IsRunning)
            {
                IsRunning = true;
                _listener.Start();
                Thread thread = new Thread(Accept);
                thread.Start();
            }
        }
        /// <summary>
        /// 开始进行监听
        /// </summary>
        private void Accept()
        {
            TCPClientHandle handle;
            while (IsRunning)
            {
                TcpClient client = _listener.AcceptTcpClient();
                if (_clientCount >= _maxClient)
                {
                    //TODO 触发事件
                }
                else
                {
                    handle = new TCPClientHandle(client);
                    _clientCount++;
                    _clients.Add(handle);

                    //TODO 创建一个处理客户端的线程并启动
                    //使用线程池来操作
                    new Thread(new ThreadStart(handle.RecevieData)).Start();
                }
            }

        }
        /// <summary>
        /// 停止服务器
        /// </summary>
        public void Stop()
        {
            if (IsRunning)
            {
                IsRunning = false;
                _listener.Stop();
                //TODO 关闭对所有客户端的连接
            }
        }
        /// <summary>
        /// 发送函数
        /// </summary>
        public void Send(string msg, TcpClient client)
        {
            //TODO
        }

        #endregion

        #region 事件

        /// <summary>
        /// 与客户端的连接已建立事件
        /// </summary>
        public event EventHandler<TCPEventArgs> ClientConnected;
        /// <summary>
        /// 与客户端的连接已断开事件
        /// </summary>
        public event EventHandler<TCPEventArgs> ClientDisconnected;

        /// <summary>
        /// 触发客户端连接事件
        /// </summary>
        /// <param name="state"></param>
        private void RaiseClientConnected(TCPClientHandle handle)
        {
            if (ClientConnected != null)
            {
                ClientConnected(this, new TCPEventArgs(handle));
            }
        }
        /// <summary>
        /// 触发客户端连接断开事件
        /// </summary>
        /// <param name="client"></param>
        private void RaiseClientDisconnected(Socket client)
        {
            if (ClientDisconnected != null)
            {
                ClientDisconnected(this, new TCPEventArgs("连接断开"));
            }
        }

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

        private void RaiseDataReceived(TCPClientHandle handle)
        {
            if (DataReceived != null)
            {
                DataReceived(this, new TCPEventArgs(handle));
            }
        }

        /// <summary>
        /// 数据发送事件
        /// </summary>
        public event EventHandler<TCPEventArgs> CompletedSend;

        /// <summary>
        /// 触发数据发送事件
        /// </summary>
        /// <param name="state"></param>
        private void RaiseCompletedSend(TCPClientHandle handle)
        {
            if (CompletedSend != null)
            {
                CompletedSend(this, new TCPEventArgs(handle));
            }
        }


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

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

        #endregion

        #region Close

        /// <summary>
        /// 关闭一个与客户端之间的会话
        /// </summary>
        /// <param name="handle">需要关闭的客户端会话对象</param>
        public void Close(TCPClientHandle handle)
        {
            if (handle != null)
            {
                _clients.Remove(handle);
                handle.Dispose();
                _clientCount--;
                //TODO 触发关闭事件

            }
        }
        /// <summary>
        /// 关闭所有的客户端会话,与所有的客户端连接会断开
        /// </summary>
        public void CloseAllClient()
        {
            foreach (TCPClientHandle handle in _clients)
            {
                Close(handle);
            }
            _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 (_listener != null)
                        {
                            _listener = null;
                        }
                    }
                    catch (SocketException)
                    {
                        //TODO 异常
                    }
                }
                disposed = true;
            }
        }
        #endregion
    }
}
Salin selepas log masuk

客户端处理封装类

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

namespace NetFrame.Net.TCP.Listener.Synchronous
{
    /// <summary>
    /// TcpListener实现同步TCP服务器 的客户端连接处理类
    /// </summary>
    public class TCPClientHandle
    {
        private TcpClient _tcpclient;

        private BinaryReader rs;

        private BinaryWriter ws;

        /// <summary>
        /// 标识是否与客户端相连接
        /// </summary>
        private bool _is_connect;
        public bool IsConnect
        {
            get { return _is_connect; }
            set { _is_connect = value; }
        }

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

        public TCPClientHandle(TcpClient client)
        {
            _tcpclient = client;
            rs = new BinaryReader(client.GetStream());
            ws = new BinaryWriter(client.GetStream());
            // NetworkStream ns = tmpTcpClient.GetStream();
            // if(ns.CanRead&&ns.CanWrite)
            _recvBuffer=new byte[client.ReceiveBufferSize];
        }

        /// <summary>
        /// 接受数据
        /// </summary>
        public void RecevieData()
        {
            int len = 0;
            while (_is_connect)
            {
                try
                {
                    len = rs.Read(_recvBuffer, 0, _recvBuffer.Length);
                }
                catch (Exception)
                {
                    break;
                }
                if (len == 0)
                {
                    //the client has disconnected from server
                    break;
                }
                //TODO 处理收到的数据
                
            }
        }
        /// <summary>
        /// 向客户端发送数据
        /// </summary>
        /// <param name="msg"></param>
        public void SendData(string msg)
        {
            byte[] data = Encoding.Default.GetBytes(msg);
            try
            {
                ws.Write(data, 0, data.Length);
                ws.Flush();
            }
            catch (Exception)
            {
                //TODO 处理异常
            }
        }

        #region 事件


        //TODO 消息发送事件
        //TODO 数据收到事件
        //TODO 异常处理事件

        #endregion

        #region 释放
        /// <summary>
        /// Performs application-defined tasks associated with freeing, 
        /// releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            _is_connect = false;
            if (_tcpclient != null)
            {
                _tcpclient.Close();
                _tcpclient = null;
            }
            GC.SuppressFinalize(this);
        }

        #endregion
    }
}
Salin selepas log masuk


Tcp服务器事件参数类

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

namespace NetFrame.Net.TCP.Listener.Synchronous
{
    /// <summary>
    /// 同步TcpListener TCP服务器事件类
    /// </summary>
    public class TCPEventArgs : EventArgs
    {
        /// <summary>
        /// 提示信息
        /// </summary>
        public string _msg;

        /// <summary>
        /// 客户端状态封装类
        /// </summary>
        public TCPClientHandle _handle;

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

        public TCPEventArgs(string msg)
        {
            this._msg = msg;
            IsHandled = false;
        }
        public TCPEventArgs(TCPClientHandle handle)
        {
            this._handle = handle;
            IsHandled = false;
        }
        public TCPEventArgs(string msg, TCPClientHandle handle)
        {
            this._msg = msg;
            this._handle = handle;
            IsHandled = false;
        }
    }
}
Salin selepas log masuk

 以上就是C#网络编程系列文章(四)之TcpListener实现同步TCP服务器的内容,更多相关内容请关注PHP中文网(www.php.cn)!


Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
3 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Cara Membuka Segala -galanya Di Myrise
4 minggu yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Direktori Aktif dengan C# Direktori Aktif dengan C# Sep 03, 2024 pm 03:33 PM

Panduan untuk Active Directory dengan C#. Di sini kita membincangkan pengenalan dan cara Active Directory berfungsi dalam C# bersama-sama dengan sintaks dan contoh.

Penjana Nombor Rawak dalam C# Penjana Nombor Rawak dalam C# Sep 03, 2024 pm 03:34 PM

Panduan untuk Penjana Nombor Rawak dalam C#. Di sini kita membincangkan cara Penjana Nombor Rawak berfungsi, konsep nombor pseudo-rawak dan selamat.

Paparan Grid Data C# Paparan Grid Data C# Sep 03, 2024 pm 03:32 PM

Panduan untuk Paparan Grid Data C#. Di sini kita membincangkan contoh cara paparan grid data boleh dimuatkan dan dieksport daripada pangkalan data SQL atau fail excel.

Akses Pengubahsuai dalam C# Akses Pengubahsuai dalam C# Sep 03, 2024 pm 03:24 PM

Panduan kepada Pengubahsuai Akses dalam C#. Kami telah membincangkan Pengenalan Jenis Pengubahsuai Akses dalam C# bersama-sama dengan contoh dan output.

C# Serialisasi C# Serialisasi Sep 03, 2024 pm 03:30 PM

Panduan untuk Pensirian C#. Di sini kita membincangkan pengenalan, langkah-langkah objek siri C#, kerja, dan contoh masing-masing.

Nombor Perdana dalam C# Nombor Perdana dalam C# Sep 03, 2024 pm 03:35 PM

Panduan Nombor Perdana dalam C#. Di sini kita membincangkan pengenalan dan contoh nombor perdana dalam c# bersama dengan pelaksanaan kod.

Corak dalam C# Corak dalam C# Sep 03, 2024 pm 03:33 PM

Panduan kepada Corak dalam C#. Di sini kita membincangkan pengenalan dan 3 jenis Corak teratas dalam C# bersama-sama dengan contoh dan pelaksanaan kodnya.

Faktorial dalam C# Faktorial dalam C# Sep 03, 2024 pm 03:34 PM

Panduan untuk Faktorial dalam C#. Di sini kita membincangkan pengenalan kepada faktorial dalam c# bersama-sama dengan contoh dan pelaksanaan kod yang berbeza.

See all articles