热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C#TCPClient开发手记

示例使用方法参考示例以下一个简单的异步事件TCP客户端实现usingNewtonsoft.Json;usingNewtonsoft.Json.Linq;usingSystem;us

示例
使用方法
参考

示例

以下一个简单的异步事件TCP客户端实现

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;

namespace Leestar54
{
    /// 
    /// 自定义回调事件参数
    /// 
    /// 泛型类返回
    public class TEventArgs : EventArgs
    {
        public T Result { get; private set; }
        public TEventArgs(T obj)
        {
            this.Result = obj;
        }
    }

    class MyTcpClient
    {
        private string md5id;
        Thread readThread;
        Thread heartbeatThread;
        TcpClient tcpClient;
        NetworkStream ns;
        //AsyncOperation会在创建他的上下文执行回调
        public AsyncOperation AsyncOperation;
        private static MyTcpClient singleton = null;
        static readonly object lazylock = new object();

        #region Event
        //回调代理中处理事件
        public event EventHandler Connected;
        public event EventHandler> Receive;
        public event EventHandler> Error;

        //AsyncOperation回调代理
        private SendOrPostCallback OnConnectedDelegate;
        private SendOrPostCallback OnReceiveDelegate;
        private SendOrPostCallback OnErrorDelegate;

        private void OnConnected(object obj)
        {
            Connected?.Invoke(this, EventArgs.Empty);
        }

        private void OnReceive(object obj)
        {
            Receive?.Invoke(this, new TEventArgs((JObject)obj));
        }

        private void OnError(object obj)
        {
            Error?.Invoke(this, new TEventArgs((Exception)obj));
        }

        #endregion

        /// 
        /// 构造函数
        /// 
        MyTcpClient()
        {
            OnConnectedDelegate= new SendOrPostCallback(OnConnected);
            OnReceiveDelegate= new SendOrPostCallback(OnReceive);
            OnErrorDelegate= new SendOrPostCallback(OnError);
        }

        /// 
        /// 单例模式
        /// 
        /// 
        public static MyTcpClient getInstance()
        {
            if (singleton == null)
            {
                lock (lazylock)
                {
                    if (singleton == null)
                    {
                        singleton = new MyTcpClient();
                    }
                }
            }
            return singleton;
        }

        //当前客户端唯一id
        public string Md5id
        {
            get
            {
                return md5id;
            }

            set
            {
                md5id = value;
            }
        }

        /// 
        /// 连接服务器
        /// 
        public void Connect()
        {

            try
            {
                tcpClient = new TcpClient("119.23.154.150", 9501);
                if (tcpClient.Connected)
                {
                    ns = tcpClient.GetStream();
                    //开启两个线程长连接,一个读取,一个心跳
                    readThread = new Thread(Read);
                    readThread.IsBackground = true;
                    readThread.Start();
                    heartbeatThread = new Thread(HeartBeat);
                    heartbeatThread.IsBackground = true;
                    heartbeatThread.Start();
                    System.Diagnostics.Debug.WriteLine("服务器连接成功");
                    this.SendMsg(JObject.FromObject(new
                    {
                        cmd = "connect"
                    }));
                }
            }
            catch (Exception e)
            {
                this.AsyncOperation.Post(OnErrorDelegate, e);
                Thread.Sleep(5000);
                ReConnect();
            }
        }
        /// 
        /// 读取接收到的数据
        /// 
        private void Read()
        {
            try
            {
                //休眠2秒让窗口初始化
                Thread.Sleep(2000);
                Byte[] readBuffer = new Byte[1024];
                while (true)
                {
                    int alen = tcpClient.Available;
                    if (alen > 0)
                    {
                        Int32 bytes = ns.Read(readBuffer, 0, alen);

                        string respOnseData= System.Text.Encoding.UTF8.GetString(readBuffer, 0, bytes);
                        //为了避免粘包现象,以\r\n作为分割符
                        string[] arr = responseData.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        foreach (var item in arr)
                        {
                            if (item != string.Empty)
                            {
                                System.Diagnostics.Debug.WriteLine("接受到消息" + item);
                                JObject jobj = JObject.Parse(item);
                                this.AsyncOperation.Post(OnReceiveDelegate, jobj);
                            }
                        }
                    }
                    Thread.Sleep(500);
                }
            }
            catch (Exception e)
            {
                this.AsyncOperation.Post(OnErrorDelegate, e);
            }
        }

        /// 
        /// 心跳线程
        /// 
        private void HeartBeat()
        {
            try
            {
                while (true)
                {
                    Thread.Sleep(8000);
                    byte[] wb = System.Text.Encoding.UTF8.GetBytes("+h");
                    ns.Write(wb, 0, wb.Length);
                }
            }
            catch (Exception e)
            {
                this.AsyncOperation.Post(OnErrorDelegate, e);
                Thread.Sleep(5000);
                ReConnect();
            }
        }

        /// 
        /// 心跳失败,则网络异常,重新连接
        /// 
        public void ReConnect()
        {
            if (readThread != null)
            {
                readThread.Abort();
            }

            Connect();
        }


        public void SendMsg(string msg)
        {
            byte[] wb = System.Text.Encoding.UTF8.GetBytes(msg);
            ns.Write(wb, 0, wb.Length);
        }

        public void SendMsg(JObject json)
        {
            SendMsg(json.ToString(Formatting.None));
        }
    }
}

使用方法
MyTcpClient client = MyTcpClient.getInstance();
//保证回调函数是在创建他的上下文执行(一般是UI线程)
client.AsyncOperation = AsyncOperationManager.CreateOperation(null);
client.Error += Client_Error; ;
client.Receive += Client_Receive; ;
client.Connected += Client_Connected;
client.Connect();

参考

http://www.cnblogs.com/kex1n/p/6502002.html
https://www.codeproject.com/Articles/14265/The-NET-Framework-s-New-SynchronizationContext-Cla
http://www.cnblogs.com/leestar54/p/4591792.html
https://msdn.microsoft.com/zh-cn/library/vs/alm/system.componentmodel.asyncoperationmanager.createoperation(v=vs.85)

附件列表

    C# TCPClient开发手记


    推荐阅读
    • Python 伦理黑客技术:深入探讨后门攻击(第三部分)
      在《Python 伦理黑客技术:深入探讨后门攻击(第三部分)》中,作者详细分析了后门攻击中的Socket问题。由于TCP协议基于流,难以确定消息批次的结束点,这给后门攻击的实现带来了挑战。为了解决这一问题,文章提出了一系列有效的技术方案,包括使用特定的分隔符和长度前缀,以确保数据包的准确传输和解析。这些方法不仅提高了攻击的隐蔽性和可靠性,还为安全研究人员提供了宝贵的参考。 ... [详细]
    • 深入解析Java虚拟机的内存分区与管理机制
      Java虚拟机的内存分区与管理机制复杂且精细。其中,某些内存区域在虚拟机启动时即创建并持续存在,而另一些则随用户线程的生命周期动态创建和销毁。例如,每个线程都拥有一个独立的程序计数器,确保线程切换后能够准确恢复到之前的执行位置。这种设计不仅提高了多线程环境下的执行效率,还增强了系统的稳定性和可靠性。 ... [详细]
    • 在 Axublog 1.1.0 版本的 `c_login.php` 文件中发现了一个严重的 SQL 注入漏洞。该漏洞允许攻击者通过操纵登录请求中的参数,注入恶意 SQL 代码,从而可能获取敏感信息或对数据库进行未授权操作。建议用户尽快更新到最新版本并采取相应的安全措施以防止潜在的风险。 ... [详细]
    • 在 Mac 上查看隐藏文件和文件夹的详细指南。通过终端命令,您可以轻松地显示或隐藏这些文件。具体步骤如下:输入 `defaults write com.apple.finder AppleShowAllFiles -bool true` 以显示所有隐藏文件,或使用 `defaults write com.apple.finder AppleShowAllFiles -bool false` 以重新隐藏它们。此方法适用于各种版本的 macOS,帮助用户更好地管理和访问系统文件。 ... [详细]
    • 本文详细解析了逻辑运算符“与”(&&)和“或”(||)在编程中的应用。通过具体示例,如 `[dehua@teacher~]$[$(id -u) -eq 0] && echo "You are root" || echo "You must be root"`,展示了如何利用这些运算符进行条件判断和命令执行。此外,文章还探讨了这些运算符在不同编程语言中的实现和最佳实践,帮助读者更好地理解和运用逻辑运算符。 ... [详细]
    • 二分查找算法详解与应用分析:本文深入探讨了二分查找算法的实现细节及其在实际问题中的应用。通过定义 `binary_search` 函数,详细介绍了算法的逻辑流程,包括初始化上下界、循环条件以及中间值的计算方法。此外,还讨论了该算法的时间复杂度和空间复杂度,并提供了多个应用场景示例,帮助读者更好地理解和掌握这一高效查找技术。 ... [详细]
    • 在 Android 开发中,`android:exported` 属性用于控制组件(如 Activity、Service、BroadcastReceiver 和 ContentProvider)是否可以被其他应用组件访问或与其交互。若将此属性设为 `true`,则允许外部应用调用或与之交互;反之,若设为 `false`,则仅限于同一应用内的组件进行访问。这一属性对于确保应用的安全性和隐私保护至关重要。 ... [详细]
    • 蚂蚁课堂:性能测试工具深度解析——JMeter应用与实践
      蚂蚁课堂:性能测试工具深度解析——JMeter应用与实践 ... [详细]
    • 在最近的项目中,我们广泛使用了Qt框架的网络库,过程中遇到了一些挑战和问题。本文旨在记录这些经验和解决方案,以便日后参考。鉴于我们的客户端GUI完全基于Qt开发,我们期望利用其强大的网络功能进行Fiddler网络数据包的捕获与分析,以提升开发效率和应用性能。 ... [详细]
    • Unity3D 中 AsyncOperation 实现异步场景加载及进度显示优化技巧
      在Unity3D中,通过使用`AsyncOperation`可以实现高效的异步场景加载,并结合进度条显示来提升用户体验。本文详细介绍了如何利用`AsyncOperation`进行异步加载,并提供了优化技巧,包括进度条的动态更新和加载过程中的性能优化方法。此外,还探讨了如何处理加载过程中可能出现的异常情况,确保加载过程的稳定性和可靠性。 ... [详细]
    • 在跨线程调用UI控件方法时,通常使用同步调用机制,如 `控件.Invoke(Delegate, 参数)`。这里需要声明并实现一个委托,因为控件本身并不知道如何处理跨线程操作。通过将具体的实现逻辑封装在委托中,控件可以正确地执行这些操作,确保线程安全性和UI的一致性。此外,为了提高性能和可维护性,建议对频繁的跨线程调用进行优化,例如使用异步调用或批量处理请求。 ... [详细]
    • 题目 E. DeadLee:思维导图与拓扑结构的深度解析问题描述:给定 n 种食物,每种食物的数量由 wi 表示。同时,有 m 位朋友,每位朋友喜欢两种特定的食物 x 和 y。目标是通过合理分配食物,使尽可能多的朋友感到满意。本文将通过思维导图和拓扑排序的方法,对这一问题进行深入分析和求解。 ... [详细]
    • 深入解析Linux内核中的进程上下文切换机制
      在现代操作系统中,进程作为核心概念之一,负责管理和分配系统资源,如CPU和内存。深入了解Linux内核中的进程上下文切换机制,需要首先明确进程与程序的区别。进程是一个动态的执行流,而程序则是静态的数据和指令集合。进程上下文切换涉及保存当前进程的状态信息,并加载下一个进程的状态,以实现多任务处理。这一过程不仅影响系统的性能,还关系到资源的有效利用。通过分析Linux内核中的具体实现,可以更好地理解其背后的原理和技术细节。 ... [详细]
    • 如何在PDF文档中添加新的文本内容?
      在处理PDF文件时,有时需要向其中添加新的文本内容。这是否可以直接实现呢?有哪些简便且免费的方法可供选择?使用极速PDF阅读器打开文档后,可以通过点击左上角的“注释”按钮切换到注释模式,并选择相应的工具进行编辑。此外,还可以利用其他功能丰富的PDF编辑软件,如Adobe Acrobat DC或Foxit PhantomPDF,它们提供了更多高级的编辑选项,能够满足更复杂的需求。 ... [详细]
    • 题目要求解决一个有趣的编程挑战,即计算由四个自然数 \( p, q, r, s \) 组成的分数序列的和。具体来说,需要编写一个 C# 程序来处理这些自然数,并通过特定的数学运算得出最终结果。该任务不仅考验编程技能,还涉及对数学公式的理解和应用。 ... [详细]
    author-avatar
    手浪用户穹谷之鹰
    这个家伙很懒,什么也没留下!
    PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
    Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有