65.9K
CodeProject 正在变化。 阅读更多。
Home

HTML5 功能:(Canvas vs GDI+)& 网页上的双工通信(Websocket vs WCF)

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.23/5 (8投票s)

2011年2月10日

CPOL

4分钟阅读

viewsIcon

58987

downloadIcon

1527

HTML5 具有一些令人兴奋的功能,允许我们构建像 Windows 应用程序一样的基于 Web 的应用程序。

背景

几个月前,我的公司举办了一场关于 HTML 5 的比赛。这让我想起了我还是学生时的 OPT 科目。我把这个想法带入比赛,以最大限度地应用 HTML 5 的特性。我在比赛中加入了两个最重要的特性

  1. 画布
  2. Websocket

应用程序中实现了三个功能

  1. 网页上的 P2P 通信
  2. 画布上的动画
  3. 网页上的订阅

引言

  • 我编写了一个 .NET Windows 窗体应用程序作为 websocket 服务器。在 Windows 应用程序中,我实现了一个 OPT 逻辑,并通过 socket 将所有关键事件开放给外部编程。实际上,任何 socket 连接都可以从服务器获取数据。
  • 我不会详细解释 OPT。基本上,问题是生产 P。

要生产 P,首先需要生产两个组件:P1 和 P2。我们可以通过销售 P 以及 P1、P2 来赚钱。P 的价格 > P1+P2 的价格。

有 3 台机器:一台红色机器,一台绿色机器,一台黄色机器,用于生产 P1、P2 和 P。

为了生产 P1,红色机器需要预热 A 分钟(我忘记了这个数字),并且生产一个 P1 需要 ** 美元。

为了生产 P2,绿色机器需要预热 B 分钟,然后在 P2 上工作 C 分钟。这是第一步。第二步是预热红色机器 D 分钟,在 P2 上工作 E 分钟。这时,红色机器将停止生产 P1(我们只有一台红色机器),然后绿色机器继续在 P2 上工作,进行第三步以完成 P2 的生产。

为了生产 P,黄色机器需要预热 F 分钟。使用一个 P1 和一个 P2,黄色机器将在 G 分钟内生产一个 P。

所有制造商都需要钱。

每周支付工资。

问题是:如何管理生产以获得最大收益。

我在窗口应用程序中放了一个我认为最好的算术计算。在您按下 GO 按钮后,应用程序将运行算术以获得最大收益。

Picture_3.png

我将 Windows 窗体上的所有效果重现在网页上。

Picture_4.png

Using the Code

WebSocket

我参考了 https://codeproject.org.cn/KB/webservices/c_sharp_web_socket_server.aspx?bcsi_scan_84C04EB1A8996739=IUdio+8K+Vb+tVCNrQ5lbwYAAABJQgES&bcsi_scan_filename=c_sharp_web_socket_server.aspx 来编写 websocket 服务器。websocket 连接最重要的部分是握手信息。当 Chrome 尝试连接一个 websocket 服务器时,它将发送一个握手信息

GET /chat HTTP/1.1 
Upgrade: WebSocket 
Connection: Upgrade 
Host: www.zendstudio.net:9108 
Origin: http://www.zendstudio.net 
Cookie: somenterCookie

当服务器获取信息时,回复

HTTP/1.1 101 Web Socket Protocol Handshake 
Upgrade: WebSocket 
Connection: Upgrade 
WebSocket-Origin: localhost
WebSocket-Location: ws:///chat

建立连接

  • 在 P、P1 和 P3 生产过程中产生的所有关键数据都将通过 websocket 订阅。定义了 3 个结构来包含这些信息
    //JSonObject has an extension method to convert the object to JSON object
    public class MileStoneMessage :JSonObject
        {
            #region Properties N:Total number; R: Remain number; S:Sales Number; 
            SR: Sales Revenue; M:Material
            public int P_N { get; set; }
            public int P_R { get; set; }
            public int P_S { get; set; }
            public decimal P_SR { get; set; }
            public int P2_N { get; set; }
            public int P2_R { get; set; }
            public int P2_S { get; set; }
            public int P2_U { get; set; }
            public decimal P2_SR { get; set; }
            public int P1_N { get; set; }
            public int P1_R { get; set; }
            public int P1_S { get; set; }
            public int P1_U { get; set; }
            public decimal P1_SR { get; set; }
            public decimal Salary { get; set; }
            public decimal MCost { get; set; }
            public decimal M_R { get; set; }
            public string T_P { get; set; }
            #endregion
        }
    public class ClientInstruction : JSonObject
        {
         
            public InstructionType Type { get; set; }
            public int Number { get; set; }
            public string Sender { get; set; }
            public string To { get; set; }
            public string Notice{ get; set; }
        }
  • Websocket 服务器也接受以下指令来控制 Windows 窗体,这意味着我们可以从网页控制 Windows 窗体。
    [DataContract]
        public enum InstructionType
        {
            [EnumMember]
            Auto=0,
            [EnumMember]
            Manual=1,
            [EnumMember]
            Start=2,
            [EnumMember]
            Pause=3,
            [EnumMember]
            Stop=4,
            [EnumMember]
            Timer=5,
            [EnumMember]
            InputP1=6,
            [EnumMember]
            InputP2=7,
            [EnumMember]
            Private = 8,//private message
            [EnumMember]
            Register = 9//new user
        }
  • 服务器发送消息
    public void SendToAll(string message)
            {
                foreach (var c in Connections)
                {
                    try
                    {
                        if (!c.Send(message)) DisposedConnections.Add(c);
                    }
                    catch
                    {
                        DisposedConnections.Add(c);
                    }
                }
                foreach (var c in DisposedConnections)
                {
                    Connections.Remove(c);
                }
                DisposedConnections.Clear();
            }
  • JavaScript 连接 websocket 服务器
    ws = new WebSocket('ws://' + document.getElementById("server").value + 
        ':8181/TWCompetition', 'ClientInstruction');
            ws.onopen = function () {
                status = 1;
                for (var i = 0; i < onOpenEventListeners.length; i++)
                    onOpenEventListeners[i]();
            }
            ws. önclose = function () {
                status = 0;
                for (var i = 0; i < onCloseEventListeners.length; i++)
                    onCloseEventListeners[i]();
            }
  • JavaScript 接收来自 websocket 的消息
            ws.onmessage = function (evt) {
                var message = eval('(' + evt.data + ')');
                switch (message.Key) {
                    case "InitData":
                        if (message.Trace.length > 0) RenderMoneyInitTrace(
                            "MoneyDashboard", message.Trace, "MoneyIcon");
                        break;
                    case "Users":
                        OnlineUsers = message;
                        DisplayUsers();
    
                        break;
                    case "Private":
                        var sender = message.Sender;
                        var conversationMessage = message.Message;
                        var name;
                        
                        if(conversationMessage=="black you"){
                            if(blackyouObj!=null) {
                                blackyouObj.OpenBlack();
                                ClosePrivateWindow("PW"+sender);
                                return;
                            }
                        }
                        for (i = 0; i < OnlineUsers.Keys.length; i++) {
                            if (OnlineUsers.Keys[i] == sender) {
                                name = OnlineUsers.Names[i];
                            }
                        }
                        PrivateConversation(sender, name, conversationMessage)
                        break;
                    case "Register":
                        Token = message.Token;
                        SendName(document.getElementById('name').value);
                        break;
                    case "OneSecond":
                        for (var i = 0; i < onSecondEventListeners.length; i++)
                            onSecondEventListeners[i](message);
                        break;
                    default:
                        for (var j = 0; j < onMilestoneEventListeners.length; j++)
                            onMilestoneEventListeners[j](message);
                        break;
                }
            }
        }
  • JavaScript 发送回指令
    var SendInstruction = function (type, number) {
        var json = JSON.stringify({ Type: type, Number: number });
        ws.Send(json);
    }

画布

在某种程度上,JavaScript 在画布上绘制形状的语法与 GDI+ 语法非常相似。JavaScript 绘制线条

ctx.beginPath();
ctx.moveTo(14, 10);
ctx.lineTo(23, 15);
ctx.lineTo(14, 20);
ctx.closePath();

JavaScript 绘制渐变

grd = ctx.createLinearGradient(0, canvas.height-mywidth, 0, canvas.height);
grd.addColorStop(0, "gray");
grd.addColorStop(0.5, "white");
grd.addColorStop(1, "gray");

如何演示

  • WindowsOpt 文件夹下,双击 opt.exe
  • 看看 Windows 窗体的右上角。选择一个可用的 IP 来建立客户端连接。

    ip.png

  • 单击 Game Control 面板上的 GO 按钮,Windows 窗体开始运行动画。

    gamecontr</p><p>•Under WebOPT folder, open WebOPT.html with the latest chrome</p><p>•Input the ip you got from the windows form into Server textbox on right upper corner and click Login (you can also input your personal name instead of keeping Will). If the connection is ok, you will see “websocket connection open” in the right Log panel. If there is “websocket connection close” means something I don’t know wrong.<img src=

  • 设置好 websocket 后,您将看到与 Windows 窗体完全相同的动画在您的网页上,您也可以控制游戏。

    pa.png status.png

  • 您还可以看到一个 thoughtworker 正在屏幕上运行

    tw.png

  • P2P 通信,有点像 Google talk
  • 在新标签页中以不同的名称登录 WebOPT.html。然后您将看到在线用户列表。您的名字是粉红色的,其他人的名字是绿色的。

    userlist.png

  • 单击列表中的某人,左下角会弹出一个对话框。

    conversation.png

  • 在其中写任何内容并按 Enter 键。然后您就进入了私人对话。

我在里面设计了一个有趣的东西,删除对话框中的所有文本并输入小写的“black you”。您正在与之交谈的人将看到一个黑屏,并显示一个有趣的表情,持续几秒钟。

您在网页中看到的所有彩色内容都是由 JavaScript 编写的。页面上没有链接到图片的图片。这就是我所说的 - HTML5 中的 Canvas 可以替代 GDI+。

© . All rights reserved.