现在的位置: 首页 > 综合 > 正文

Ajax程序模拟SOCKET套接字编程

2013年08月19日 ⁄ 综合 ⁄ 共 5106字 ⁄ 字号 评论关闭

Ajax程序模拟SOCKET套接字编程
Ajax, 套接字, SOCKET, 程序, 模拟
在家无聊,重新看了下AJAX最底层的原理,因为不喜欢一直用被人封装了不知道几层的东西,所以就自己写了个不倚靠其他函数库的程序。并且用一个网页上的无刷新聊天室做例子来模拟SOCKET套接字编程。前台没的说,肯定用JavaScript。后台我用了自己熟悉的ASP.NET(C#)。其实于语言无关,各位可以用自己的解决方案轻松移植。(应该等能接受GET和POST请求吧,呵呵。我这是废话)
客户端核心代码。
<div id="divChatingDisplay"></div>做为实时显示聊天内容的区域
<p>
            姓名:<input id="txtName" style="width: 100px" type="text" />说:
            <input id="txtContent" type="text" style="width: 500px" />
            <input id="Sender" type="button" value="发送" /></p>
一个简单的控制界面,这里不涉及用户身份验证系统。(史上最简陋的界面)
function createXMLHttpRequest()
{
    if(window.ActiveXObject)
    {
        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    else if(window.XMLHttpRequest)
    {
        xmlHttp = new XMLHttpRequest()
    }
}
构件一个XML形式的HTTP请求,默认大家用的都是IE浏览器(在中国最流行的一种)
function SendChatMessage()
{
    createXMLHttpRequest();
           
    var strName    = txtName.value;
    var strContent = txtContent.value;
    var url        = "bg_ChatInput.aspx";
    var form       = "name=" + strName + "&content=" + strContent;
           
    xmlHttp.open("POST",url,true);
    xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
    xmlHttp.send(form);
}
模拟浏览器发送POST的请求,在POST里写上各个需要传到服务器端的内容,发言的人和发言的内容。出于考虑到有些人可能话比较多,所以没有GET请求。POST传输的数据量最多达到4G,应该不会有那么话多人的,呵呵(真有一句话超过4GB的就踢了)。这里的bg_ChatInput.aspx是后台把聊天内容放进数据库的后台程序。下文会介绍它的实现方法。
function GetMessage()
{
    createXMLHttpRequest();
       
    var url = "bg_ChatGetInfo.aspx"          
   xmlHttp.onreadystatechange = handleStateChange;
   xmlHttp.open("GET",url,true);
   xmlHttp.send(null);
   Refresh();
}
实时获得消息的函数,因为不涉及任何要传输的参数,所以用GET请求。bg_ChatGetInfo.aspx是后台一直获取消息的函数。处理收到的消息使用handleStateChange函数,这里用函数指针把.onreadystatechange 事件触发的函数指向handleStateChange。
function handleStateChange()
{
   if(xmlHttp.readyState == 4)
   {
       if(xmlHttp.status == 200)
       {
           var content = xmlHttp.responseText;
           divChatingDisplay.innerHTML=content;
       }
       else
       {
           window.alert("An error occurred: " + xmlHttp.statusText);
       }
    }       
}
这里包含了一个简单的错误处理,详细情况可以参考一下关于微软的XMLHttpRequest对象的参考文档,这里没有什么处理,就是把接受到的数据简单得写入到divChatingDisplay中,并且以HTML格式。至此,我们的客户端还差一个定期查询更新内容的函数来模拟SOCKET中的监听线程。
function Refresh()
{
    window.setTimeout("GetMessage()",1000);
}
在HTML头上添加<body>
我们注意,在刚刚的GetMessage函数最后套用了Refresh()函数,这样每1000毫秒都会执行一次GetMessage()函数,就模仿了SOCKET中的监听线程所做的工作,这样可以每次都能收到最新消息(这样放在另一个函数,而不是放在GetMessage函数里是让页面载入1秒后才开始获取信息,让界面充分载入后再加载数据,看上去比较高级哈.别把界面弄得太复杂,否则就看不出效果了)。这是客户端最需要注意的技巧。接下来我们完成了客户端所有的开发工作。
服务器端开发
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
    protected void Page_Load(object sender, EventArgs e)
    {
        string strName    = Request.Form["name"].ToString();
        string strContent = Request.Form["content"].ToString();
        string strTime = DateTime.Now.ToString("T");
        string connString = @"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + AppDomain.CurrentDomain.BaseDirectory + @"App_Data/db_InfoExchange.mdb";
        string strSql = string.Format("INSERT INTO [tb_Chat] ([sender],[content],[time]) VALUES ('{0}','{1}','{2}')",strName,strContent,strTime);
        OleDbConnection conn = new OleDbConnection(connString);
        OleDbCommand cmd = new OleDbCommand(strSql, conn);
        conn.Open();
        int res = cmd.ExecuteNonQuery();
        conn.Close();
    }
</script>
一个很粗糙的ASP.NET程序,不需要任何界面.选用ACCESS做数据库,数据库设计也不介绍了.收到POST请求后获取name和content两个数据项后生成一个insert语句。添加到数据库中,注意我们接受刚刚用JavaScript模拟出来的POST请求。bg_ChatInput.aspx完成。
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
    public int count = 0;
   
    protected void Page_Load(object sender, EventArgs e)
    {
        Response.AddHeader("Cache-control", "No-cache");
        Response.AddHeader("Pragma", "No-cache");
       
        string connString = @"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=" + AppDomain.CurrentDomain.BaseDirectory + @"App_Data/db_InfoExchange.mdb";
        string strSql = "SELECT * FROM [tb_Chat]";
       
        OleDbConnection conn = new OleDbConnection(connString);
        OleDbCommand cmd = new OleDbCommand(strSql, conn);
        OleDbDataReader reader;
       
        conn.Open();
        reader = cmd.ExecuteReader();
        while (reader.Read())
        {
            Response.Write("<p><font size=2>"+reader["sender"].ToString() + " 说:" + reader["content"].ToString() + "</font></p>");
            count++;
        }
        reader.Close();
        if (count >= 10)
        {
            string sqlDelete = "DELETE FROM [tb_Chat]";
            OleDbCommand cmdDelete = new OleDbCommand(sqlDelete, conn);
            int redDelete = cmdDelete.ExecuteNonQuery();
        }
        conn.Close();
    }
</script>
这里需要特别注意的是一个烦恼了我很长时间的问题,虽然我每次都有新的请求发向服务器,但客户端并没有每次都更新数据,经过我发疯一样得寻找原因发现原来是浏览器太高级了,习惯从缓存中获取数据。(避免频繁得向服务器要信息,再成堵塞.可我要的就是这个效果呀)为了每次都确保它能从服务器获取新的更新过的数据,必须要在文件前追加两个语句:
Response.AddHeader("Cache-control", "No-cache");
Response.AddHeader("Pragma", "No-cache");
不同的后台程序都不一样,大家可以自己查看自己语言的写法,每个后台都有类似的功能。(具体怎么回事情,大家可以翻HTTP协议的原始定义)
接着要说明的是,每次获取更新请求后(每个用户都会每阁1秒发一次请求)都从数据库里获取信息,并追加修饰,确定字体大小,颜色等等,因为客户端的数据处理只是简单得写入DIV中,所以一切按照HTML标准就可以了。这里为了防止大量的历史数据,每增加10条就会把数据库清空,我承认这不是一个很好的用户体验。但ACCESS数据库的支持实在不怎么样。诸如:
Delete top(1) from tb_Chat
的SQL语句是不支持的,所以只能一古脑都删干净咯,如果你使用其他格式的数据库就会解决这个问题。
至次,模拟了SOCKET套接字编程。一来一去都有,而且实时更新数据,模拟了监听进程。这一切都被很好的保护着。用户不会感到一丝的不自然,整个页面没有任何频闪,只有别人聊天记录被刷新,而且没有帕塔帕塔的刷新的声音,很安静,很智能。(像是某洗衣机的广告词,呵呵)。给志同道合的朋友们做个交流,呵呵。

抱歉!评论已关闭.