基于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为客户端。

原文地址:https://www.cnblogs.com/scy251147/p/3392688.html