zoukankan      html  css  js  c++  java
  • 基于IHttpAsyncHandler的TCP收发器

    上一篇文章中,我们提到使用IHttpAsyncHandler来进行UDP的收发操作。由于UDP模型比较简单,所以运行没什么问题。这一篇我主要是使用IHttpAsyncHandler来进行TCP的收发操作。由于TCP的模型比较复杂,所以在设计的时候,稍微麻烦了一些。

    核心讲解

    首先,我贴上代码,然后来逐一讲解:

    using System;
    using System.Web;
    using System.Net.Sockets;
    using System.Net;
    using System.Text;
    using System.IO;
    
    namespace SocketViaWeb
    {
        #region 写日志
    
        public static class Logger
        {
            //写日志
            public static void WriteLog(string content)
            {
                try
                {
                    string timeStamp = DateTime.Now.ToString("yyyyMMdd");
                    string filePath = "C:\TestLog." + timeStamp + ".txt";
                    string contentAll = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + ":" + content + Environment.NewLine;
                    byte[] b = Encoding.Default.GetBytes(contentAll);
                    using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
                    {
                        fs.Write(b, 0, b.Length);
                        fs.Flush();
                    }
                }
                catch (Exception ex) { }
            }
        }
        #endregion
    
        #region 返回异步执行结果
        public class MyAsyncResult : IAsyncResult
        {
            public HttpContext contex;
            public AsyncCallback cb;
            public object extraData;
    
            public bool isCompleted = false;
    
            public MyAsyncResult(HttpContext contex, AsyncCallback cb, object extraData)
            {
                this.contex = contex;
                this.cb = cb;
                this.extraData = extraData;
            }
    
            public void send(string resultStr)
            {
                this.contex.Response.Output.Write(resultStr);
            }
    
            public object AsyncState
            {
                get { return null; }
            }
    
            public System.Threading.WaitHandle AsyncWaitHandle
            {
                get { return null; }
            }
    
            public bool CompletedSynchronously
            {
                //在网络连接或者流读取中,这里需要设置为True,否则前台是不能显示接收数据的。
                get { return true; }
            }
    
            public bool IsCompleted
            {
                get { return isCompleted; }
            }
        }
        #endregion
    
        #region 异步执行对象
        public static class myAsyncFunction
        {
            private static string resultResponse = string.Empty;  //获取客户端数据
            private static TcpListener tcpListener;  
    
            private static MyAsyncResult asyncResult;  //通知回传对象
            
            // 把一个异步的请求对象传入以便于供操作
            public static void Init(MyAsyncResult result,int port)
            {
                asyncResult = result;
                if (tcpListener == null)
                {
                    try
                    {
                        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("192.168.0.100"),port);
                        tcpListener = new TcpListener(endPoint);
                        tcpListener.Start();
                    }
                    catch (System.Net.Sockets.SocketException ex)
                    {
                        tcpListener = null;
                        throw new Exception(ex.Message);
                    }
                }
            }
    
            //接收客户端数据并将数据打印到前台
            public static void AcceptClients()
            {
                    TcpClient client = tcpListener.AcceptTcpClient();
                    byte[] bufferResult = new byte[1024];
                    NetworkStream readStream = client.GetStream();
                    readStream.Read(bufferResult, 0, bufferResult.Length);
                    resultResponse = System.Text.Encoding.Default.GetString(bufferResult);
    
                    Logger.WriteLog("Receiving TCP Client Message: " + resultResponse);
                    asyncResult.send(resultResponse);
            }
        }
        #endregion
    
        #region 异步执行请求
        public class AsyncSocketHandler : IHttpAsyncHandler
        {
            private static object obj = new object();
    
            public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
            {
                lock (obj)
                {
                    int port = Int32.Parse(context.Request.QueryString["port"].ToString());
                    MyAsyncResult asyncResult = new MyAsyncResult(context, cb, extraData);  //实例
                    myAsyncFunction.Init(asyncResult, port); //接收所有传入的异步对象
                    myAsyncFunction.AcceptClients();   //处理所有传入的异步对象
                    asyncResult.isCompleted = true;
                    return asyncResult;
                }
            }
    
            public void EndProcessRequest(IAsyncResult result)
            {
                MyAsyncResult asyncResult = result as MyAsyncResult;
                if (asyncResult != null)
                {
                    asyncResult.send(string.Empty);
                }
            }
    
            public bool IsReusable
            {
                get { return false; }
            }
    
            public void ProcessRequest(HttpContext context)
            { }
        }
        #endregion
    }
    View Code

    对于WriteLog函数,我就不讲了,主要是用来写日志的。
    对于MyAsyncResult类,主要是用来接收处理状态并返回,在EndProcessRequest(IAsyncResult result)中可以还原对象,然后做一些善后的工作,比如关闭数据库,清空缓存等等。

    对于myAsyncFunction类,这是我们执行的主体,里面的AcceptClients函数是我们执行的核心。

    对于AsyncSocketHandler类,它继承自异步handler:IHttpAsyncHandler,主要是用来进行异步处理的。

    在下面的代码中:

            public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
            {
                lock (obj)
                {
                    int port = Int32.Parse(context.Request.QueryString["port"].ToString());
                    MyAsyncResult asyncResult = new MyAsyncResult(context, cb, extraData);  //实例
                       myAsyncFunction.Init(asyncResult, port); //接收所有传入的异步对象
                       myAsyncFunction.AcceptClients();   //处理所有传入的异步对象
                       asyncResult.isCompleted = true;
                    return asyncResult;
                }
            }

    首先实例化MyAsyncResult对象,以便创建返回参数;然后初始化调用对象;初始化之后,开始调用我们的核心对象,也就是利用TCP接收Client的连接。最后返回执行对象。

      public void EndProcessRequest(IAsyncResult result)
            {
                MyAsyncResult asyncResult = result as MyAsyncResult;
                if (asyncResult != null)
                {
                    asyncResult.send(string.Empty);
                }
            }

    当异步执行完毕之后,就会进入EndProcessRequest函数,这个函数主要通过还原MyAsyncResult对象,实现清理等操作,这里我就不再赘述。

    那么如何调用呢?

    调用其实很简单,通过Ajax请求这个异步Handler,然后利用其Success方法打印出获取的对象就可以了。 需要注意的是,在Success方法中,我们可以再调用Ajax请求来实现循环获取Client Sockets。

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Server.aspx.cs" Inherits="SocketViaWeb.Server" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title>TCP服务器端</title>
        <style type="text/css">
        body
        {
            font-size:12px;
        }
        </style>
        <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
        <script type="text/javascript">
            $(document).ready(function () {
                $("#btnListen").bind("click", function () {
                    //setInterval(TriggerAjax, 1000);
                    TriggerAjax();
                });
            });
    
            var array = new Array();
    
            var TriggerAjax = function () {
                var port = $("#txtPort").val();
                $.ajax({
                    type: "GET",
                    url: "AsyncSocketHandler.ashx?port=" + port,
                    dataType: "text",
                    success: function (result) {
                        if (result != "") {
                            var myDate = new Date();
                            var message = myDate.toLocaleString() + " : " + result;
                            if (!array.contains(result)) {
                                $("#msg").append(message).append("<br>");
                            }
                        }
                        TriggerAjax();  //循环调用
                    },
                    error: function (result) {
                        TriggerAjax();  //循环调用
                    }
                });
            }
    
            Array.prototype.contains = function (elem) {
                for (var i = 0; i < this.length; i++) {
                    if (this[i] == elem) {
                        return true;
                    }
                }
                return false;
            } 
    
        </script>
    </head>
    <body>
        <div style="height: 390px;  435px;float:left;border:1px solid #B7D6BF;">
            <div style="height:30px;100%;float:left;background:url('images/navEx.gif') repeat-x;line-height:30px;text-align:center;"><strong>服务端接收数据</strong></div>
            <div style="float:left;100%;height:310px;border-bottom:1px solid #B7D6BF; overflow-x:auto;" id="msg"></div>
            <div style="float:left;100%;height:50px;text-align:right;line-height:50px;">
                绑定的本机端口:<input id="txtPort" type="text" style="40px;border:none;border-bottom:1px solid black;" value="10004" />
                <input id="btnListen" type="button" value="监听" style="border:none;background:url('images/btn.gif') no-repeat;50px;height:20px;color:White;" />
                <input id="btnStop" type="button" value="停止" style="border:none;background:url('images/btn.gif') no-repeat;50px;height:20px;color:White;" onclick="return btnStop_onclick()" />
                </div>
        </div>
    </body>
    </html>
    View Code

    实现效果

    最后看看我们实现的效果吧:

     

    源码下载

    点击这里下载源码

    由于源码中有SignalR的示例,附件过大,我已经删除了相关的Signr附件,编译的时候,请首先运行 Install-Package Microsoft.AspNet.SignalR -version 1.0

     来获取相关的版本。我百度网盘放了全版本的:http://pan.baidu.com/s/15SDGG

    解决方案中的SocketViaWeb项目下的Server.aspx 为服务端,Client.aspx为客户端。

  • 相关阅读:
    Android Studio 2.2.2导入Eclipse中创建的项目
    mvc上传到云虚拟机的问题解决
    基于矢量数据的逆地理编码功能实现
    离线地图解决方案(二):地图基本控制
    离线地图解决方案(一):加载瓦片地图
    离线地图解决方案
    openlayers应用“四”:百度地图纠偏续
    openlayers应用“三”:百度地图纠偏
    openlayers应用(二):加载百度离线瓦片
    openlayers3应用一:显示百度地图
  • 原文地址:https://www.cnblogs.com/scy251147/p/3392688.html
Copyright © 2011-2022 走看看