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

原创 2015年03月15日 18:03:48

原创性声明

本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处

文章系列目录

C#网络编程系列文章(一)之Socket实现异步TCP服务器 

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

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

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

C#网络编程系列文章(五)之Socket实现异步UDP服务器

C#网络编程系列文章(六)之Socket实现同步UDP服务器

C#网络编程系列文章(七)之UdpClient实现异步UDP服务器

C#网络编程系列文章(八)之UdpClient实现同步UDP服务器

本文介绍

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
    }
}
客户端处理封装类

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

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



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

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 本文介绍 TcpListen...

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

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 ...
  • Sayesan
  • Sayesan
  • 2017年12月13日 10:00
  • 6

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

原创性声明 本文作者:小竹zz  本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 本文介绍 在上一篇博客中我...

C#网络编程系列文章(六)之Socket实现同步UDP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 ...
  • Sayesan
  • Sayesan
  • 2017年12月13日 10:01
  • 15

C#网络编程系列文章(八)之UdpClient实现同步UDP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 文章系列目录 ...
  • Sayesan
  • Sayesan
  • 2017年12月13日 10:03
  • 10

C#网络编程系列文章(八)之UdpClient实现同步UDP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 文章系列目录 C#网络编程系...

C#网络编程系列文章(六)之Socket实现同步UDP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 本文介绍 在.Net中,S...

C#网络编程系列文章(一)之Socket实现异步TCP服务器

原创性声明 开篇 本人因为对于网络编程的喜爱,经常性的使用c#编写各类服务器(e.g TCP服务器,UDP服务器),但是基本上都是搞着玩,网上也有很多讲c#网络编程的文章,当然我也参考了很多作者写...

网络编程系列文章(一)之Socket实现异步TCP服务器

同一个面试问题并非只有一个答案,而同一个答案并不是在任何面试场合都有效。对于应聘者而言,虽然不同的公司具有不同的产品形态,但各大公司相同的职位都需要具备大同小异的基本工作技能。在这篇文章中,我们将分享...

C#网络编程系列文章(五)之Socket实现异步UDP服务器

原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 本文介绍 在.Net中,Sy...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C#网络编程系列文章(四)之TcpListener实现同步TCP服务器
举报原因:
原因补充:

(最多只允许输入30个字)