很难把UDP和Asp.net扯到一起,但是由于最近项目中需要通过网页发送控制指令到中间件,再由中间件发送到下位机的需求。所以就研究了一下是否可以通过asp.net操控UDP Socket实现数据的收发,结果证明是可以的。

服务端代码逻辑

在这个实现过程中,其核心组件就是IHttpAsyncHandler接口,相信大家都明白IHttpHandler是来干什么用的,那么IHttpAsyncHandler就是其异步版本,可以实现操作的异步进行。并且由于这个接口提供了事件完成回调机制,所以能够非常方便的将执行结果打印到前台来。这个接口包含了两个比较有用的方法,一个是BeginProcessRequest,代表异步操作的开始,另外一个是EndProcessRequest,代表异步操作的结束。一般在使用的时候,我们需要结合IAsyncResult接口一起使用,以便能够非常方便的实现完成回调的通知。

下面主要来讲解一下代码逻辑。

首先,需要继承自IHttpAsyncHandler接口,这里暂时先不提供实现:

    #region 异步执行请求
    public class AsyncSocketHandler : IHttpAsyncHandler,IRequiresSessionState
    {
        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
        {
            //开始请求
        }
 
        public void EndProcessRequest(IAsyncResult result)
        {
            //请求结束
        }
        public bool IsReusable
        {
            get { return false; }
        }
 
        public void ProcessRequest(HttpContext context)
        { }
    }
    #endregion

然后,我们最好能够引用IAsyncResult接口并提供其实现,以便于回传通知:

#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.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

上面的实现很简单,其实就是一个带参构造,然后利用Send方法向前台打印数据。

最后就是我们真正要运行在异步进程中的方法:

 
    #region 异步执行对象
    public static class myAsyncFunction
    {
        private static string resultResponse = string.Empty;  //获取客户端数据
        private static UdpClient udpClient;  
        private static IPEndPoint remoteEndPoint;
 
        private static myAsyncResult asyncResult;  //通知回传对象
        
        // 把一个异步的请求对象传入以便于供操作
        public static void Init(myAsyncResult result,int port)
        {
            asyncResult = result;
            if (udpClient == null)
            {
                try
                {
                    udpClient = new UdpClient(port);
                }
                catch (System.Net.Sockets.SocketException ex)
                {
                    udpClient = null;
                    throw new Exception(ex.Message);
                }
            }
        }
 
        //接收客户端数据并将数据打印到前台
        public static void AcceptClients()
        {
            byte[] bufferResult = udpClient.Receive(ref remoteEndPoint);
            resultResponse = System.Text.Encoding.ASCII.GetString(bufferResult);
            WriteLog("ReceivingClient: " + resultResponse);
            asyncResult.send(resultResponse);
        }
        //数据接收完毕,服务器端回送消息给客户端
        public static void ResponseClients()
        {
            string message = "Server has received your message.";
            byte[] msgBytes = Encoding.Default.GetBytes(message);
            IPEndPoint sEndPoint = new IPEndPoint(remoteEndPoint.Address, 10003);
            UdpClient sClient = new UdpClient();
            sClient.Connect(sEndPoint);
            sClient.Send(msgBytes,msgBytes.Length);
        }
 
        //写日志
        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
都写完以后,我们需要对IHttpAsyncHandler接口进行实现:
#region 异步执行请求
    public class AsyncSocketHandler : IHttpAsyncHandler,IRequiresSessionState
    {
        private static object obj = new object();
        private static object objEx = 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)
        {
            myAsyncFunction.ResponseClients();  //服务端发送客户端的应答
        }
        public bool IsReusable
        {
            get { return false; }
        }
        public void ProcessRequest(HttpContext context)
        { }
    }
    #endregion

由于代码比较简单,我这里不做过多的讲解,逻辑顺序就是,通过BeginProcessRequest方法处理所有传入的异步执行对象,然后执行;执行完毕之后,通过IAsyncResult接口打印数据到前台去。
 
上面的是服务端部分,接口写完后,如何调用呢?方法很简单,我直接贴出前台代码:
<%@ 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>UDP服务器端</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 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();
                    $("#msg").append(myDate.toLocaleString() + " : " + result).append("<br>");
                    //}
                },
                error: function (result) {
                    debugger;
                }
            });
        }
    </script>
</head>
<body>
    <div style="height: 390px; width: 435px;float:left;border:1px solid #B7D6BF;">
        <div style="height:30px;width:100%;float:left;background:url('images/navEx.gif') repeat-x;line-height:30px;text-align:center;"><strong>服务端接收数据</strong></div>
        <div style="float:left;width:100%;height:310px;border-bottom:1px solid #B7D6BF; overflow-x:auto;" id="msg"></div>
        <div style="float:left;width:100%;height:50px;text-align:right;line-height:50px;">
            绑定的本机端口:<input id="txtPort" type="text" style="width: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;width:50px;height:20px;color:White;" /></div>
    </div>
</body>
</html>


在前台,我是通过一个轮询来每隔1秒钟检测一次UDP Socket连接,如果当前有数据传来,那么就会显示到页面上。这里就是服务端的所有部分。

客户端代码逻辑

至于客户端,我就不细说了,和正常的UDP socket发送的写法一样:

using System;
using System.Net.Sockets;
using System.Net;
using System.Text;
 
namespace SocketViaWeb
{
    public partial class Client : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
                port = Int32.Parse(txtPort.Value);
                endPoint = new IPEndPoint(IPAddress.Parse("192.168.0.100"), port);
                if (client == null)
                {
                    client = new UdpClient();
                }
        }
        private int port;
        private static UdpClient client;
        private static IPEndPoint endPoint;
 
        protected void btnListen_Click(object sender, EventArgs e)
        {
            SendContentViaUDP(txtMsg.Text);
        }
        private void SendContentViaUDP(string content)
        {
            client.Connect(endPoint);
            byte[] byteToSend = Encoding.Default.GetBytes(content);
            client.Send(byteToSend, byteToSend.Length);
        }
    }
}

效果展示

好了,我们开始运行程序,并且同时打开两个窗口,一个是客户端,一个是服务器端,看看效果吧:

源码下载

点击这里下载

基于IHttpAsyncHandler的UDP收发器的更多相关文章

  1. 基于IHttpAsyncHandler的TCP收发器

    上一篇文章中,我们提到使用IHttpAsyncHandler来进行UDP的收发操作.由于UDP模型比较简单,所以运行没什么问题.这一篇我主要是使用IHttpAsyncHandler来进行TCP的收发操 ...

  2. 【原创】NIO框架入门(二):服务端基于MINA2的UDP双向通信Demo演示

    前言 NIO框架的流行,使得开发大并发.高性能的互联网服务端成为可能.这其中最流行的无非就是MINA和Netty了,MINA目前的主要版本是MINA2.而Netty的主要版本是Netty3和Netty ...

  3. 【原创】NIO框架入门(一):服务端基于Netty4的UDP双向通信Demo演示

    申明:本文由作者基于日常实践整理,希望对初次接触MINA.Netty的人有所启发.如需与作者交流,见文签名,互相学习. 学习交流 更多学习资料:点此进入 推荐 移动端即时通讯交流: 215891622 ...

  4. Java Socket实现基于TCP和UDP多线程通信

    一.通过Socket实现TCP编程 1.1 TCP编程 TCP协议是面向连接,可靠的,有序的,以字节流的方式发送数据.基于TCP协议实现网络通信的类有客户端的Socket类和服务器端的ServerSo ...

  5. 基于C#的UDP协议的同步实现

    一.摘要 总结基于C#的UDP协议的同步通信. 二.实验平台 Visual Studio 2010 三.实验原理 UDP传输协议同TCP传输协议的区别可查阅相关文档,此处不再赘述. 四.实例  4.1 ...

  6. 基于TCP和UDP的socket

    为什么学习socket 你自己现在完全可以写一些小程序了,但是前面的学习和练习,我们写的代码都是在自己的电脑上运行的,虽然我们学过了模块引入,文件引入import等等,我可以在程序中获取到另一个文件的 ...

  7. 基于TCP与UDP协议的socket通信

    基于TCP与UDP协议的socket通信 C/S架构与初识socket 在开始socket介绍之前,得先知道一个Client端/服务端架构,也就是 C/S 架构,互联网中处处充满了 C/S 架构(Cl ...

  8. Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型

    Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...

  9. 基于Socket的UDP发包程序

    UDP(User Datagram Protocol,用户数据报协议)是在互联网中常用的传输层协议,该协议提供了向另一用户程序发送的消息的最简便的协议机制.与TCP一样,其默认的下层协议是IP.UDP ...

随机推荐

  1. 每日Scrum--No.5

    Yesterday:学习并编写代码 Today:组织小组开一次阶段性的总结会议:讨论需求分析中存在的问题:继续学习和编写代码:总结前阶段代码出现的问题 Problem:编程要注意很多的特殊情况,程序成 ...

  2. 论近年来IT媒体的怪现象

    之前在Svbtle上看过一篇文章干掉这帮搞IT新闻的!,作者因为CNET曲解原意,称Instagram要单方面售卖用户自己照片的乌龙事件,致使内心遭受严重刺激,怒吼出「科技媒体记者都应该被枪毙」的言论 ...

  3. PYTHON3 urllib2库

    python 3.x中urllib库和urilib2库合并成了urllib库..其中urllib2.urlopen()变成了urllib.request.urlopen() urllib2.Reque ...

  4. mysql数据库---同时插入两个表以上的数据

    mysql数据库问题,如何同一个操作添加两个表(a表,b表),并把b表的id添加到a表字段中,b表id自动增长 在数据库中创建存储过程,比如存储过程的名字叫做 test在java中和正常使用sql的方 ...

  5. Swing应用开发实战系列之一:自定义JdbcTemplate

    笔者本人真正意义上接触编程开发是在2004年,最早用的就是VB,然后是Delphi等,后来转到.Net,中间断断续续还用过PowerBuilder等,无一例外,所研发设计的项目或系统都是WinForm ...

  6. Java API 快速速查宝典

    Java API 快速速查宝典 作者:明日科技,陈丹丹,李银龙,王国辉 著 出版社:人民邮电出版社 出版时间:2012年5月 Java编程的最基本要素是方法.属性和事件,掌握这些要素,就掌握了解决实际 ...

  7. poj 3169 Layout 差分约束模板题

    Layout Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6415   Accepted: 3098 Descriptio ...

  8. python判断字符串,str函数isdigit、isdecimal、isnumeric的区别

    s为字符串s.isalnum() 所有字符都是数字或者字母s.isalpha() 所有字符都是字母s.isdigit() 所有字符都是数字s.islower() 所有字符都是小写s.isupper() ...

  9. Swift学习笔记--变量与常量

    1.Swift是一门强类型语言,不能为变量赋予其自身数据类型之外的值: 2.声明变量使用var关键字,声明常量使用let关键字: 3.声明变量或常量时没有对其指定类型且赋予了初值,则编译器会自动推断常 ...

  10. windows server 2003下安装.net framework 3.5 一直安装不成功

    安装包是在微软下载中心下的197m的文件 重启了也是不行,最后 找到.net framework 3.5 sp1 一个237m的安装包 安装成功了! Congratulations ! ​