微软透露开发多款Bing Win8内置应用细节

早前,微软为Windows 8以及RT用户带来了多项软件更新,其中包括了新闻、天气、金融、体育、旅游以及地图等多个软件。今天,微软又为用户带来了他们是如何开发这些软件的更多信息。据Windows 8软件开发者官方博客透露,Bing开发团队是在一年之前创建的。所有由这支团队开发的Bing内置软件软件都是基于HTML/Java Script,除了地图软件之外,其采用的是XAML/C#。

Find the weather conditions for your places of interest.

另外,所有的软件还都采用了客户端缓存技术。
微软表示之所以开发出这么多内置应用的部分原因则是为了给Win8第三方软件开发商提供模板,比如所有的Bing内部应用都支持快速视图、顶部导航栏、底部命令控制栏等模式。
如果想要更加详细地了解微软是如何设计以及如何创建出这些软件的话,可以去官方博客进行了解。

VB6硬件检测

Function QOC(CCS, MCS)
     If CCS = MCS Then
         Set wReg = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
         wReg.GetDWORDValue &H80000002, "HARDWARE\DESCRIPTION\System\CentralProcessor\0", "~MHz", strValue
         OC = strValue: Set wReg = Nothing
         Else
         OC = CCS
     End If
     QOC = OC: If QOC Mod 2 = 1 Then QOC = QOC + 1
 End Function
 
 Function wDate(nD)
     If Not IsNull(nD) Then
     wDate = CDate(Mid(nD, 5, 2) & "/" & Mid(nD, 7, 2) & "/" & Left(nD, 4) & " " & Mid(nD, 9, 2) & ":" & Mid(nD, 11, 2) & ":" & Mid(nD, 13, 2))
     End If
 End Function
 
 Function JZCS()
     NumMsg = vbCrLf & "———————————简易CPU基准测试———————————" & vbCrLf
     Dim I, T1, T2, Tempvalue, aRunTime, bRunTime
     T1 = Timer()
     For I = 1 To 2000000
         Tempvalue = 2 ^ 0.5
     Next
     T2 = Timer()
     aRunTime = FormatNumber((T2 - T1) * 1000, 2)
     NumMsg = NumMsg & "CPU 200万次开方计算所需时间:" & aRunTime & " 毫秒" & vbCrLf
     T1 = Timer()
     For I = 1 To 6000000
         Tempvalue = 1 + 1
     Next
     T2 = Timer()
     bRunTime = FormatNumber((T2 - T1) * 1000, 2)
     NumMsg = NumMsg & "CPU 600万次加法计算所需时间:" & bRunTime & " 毫秒" & vbCrLf
     JZCS = NumMsg
 End Function

Private Sub Command1_Click()
If Text1.Text = "" Or Text2.Text = "" Or Text3.Text = "" Then Exit Sub
'gethardwareinformation
 On Error Resume Next
 Dim WMI, WS, Fso
 Set WMI = GetObject("Winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
 Set cOSs = WMI.ExecQuery("Select * from Win32_OperatingSystem")
 For Each oOS In cOSs
     OSx = oOS.Caption & " " & oOS.CSDVersion & " " & oOS.Version & " (" & oOS.OSArchitecture & ")" & vbCrLf
     If CStr(Err.Number) <> 0 Then OSx = oOS.Caption & " " & oOS.CSDVersion & " " & oOS.Version & vbCrLf
 Next
 BBx = "————————————主板信息————————————" & vbCrLf
 Set Board = WMI.InstancesOf("Win32_BaseBoard")
 Set Bios = WMI.InstancesOf("Win32_Bios")
 For Each oBoard In Board
 BBx = BBx _
     & "主板名称: " & oBoard.Product & vbTab & oBoard.Version & vbCrLf _
     & "制造厂商: " & oBoard.Manufacturer & vbCrLf
 Next
 For Each oBios In Bios
 BBx = BBx _
     & "BIOS厂商: " & oBios.Manufacturer & vbCrLf _
     & "BIOS日期: " & FormatDateTime(wDate(Trim(oBios.ReleaseDate)), 1) & vbCrLf _
     & "BIOS版本: " & oBios.SMBIOSBIOSVersion & vbCrLf _
     & "OEM 版本: " & oBios.Version & vbCrLf
 Next
 Set Bios = Nothing: Set Board = Nothing
 
 CPUx = "———————————处理器信息———————————" & vbCrLf
 Set CPUs = WMI.InstancesOf("Win32_Processor")
 Set Caches = WMI.InstancesOf("Win32_CacheMemory")
 For Each ObjCPU In CPUs
 MCS = ObjCPU.MaxClockSpeed: CCS = ObjCPU.CurrentClockSpeed
 If MCS Mod 2 = 1 Then MCS = MCS + 1
 If CCS Mod 2 = 1 Then CCS = CCS + 1
 OC = QOC(CCS, MCS)
 If (OC - MCS) > 10 And (OC - MCS) > 0 Then OCLC = "  超频比率: " & FormatPercent((OC - MCS) / MCS)
 If (OC - MCS) < -10 And (OC - MCS) < 0 Then OCLC = "  降频比率: " & FormatPercent((OC - MCS) / MCS)
 CPUx = CPUx _
      & "CPU 名称: " & Trim(ObjCPU.Name) & vbCrLf _
      & "CPU 构架: " & ObjCPU.Description & vbCrLf _
      & "制造厂商: " & ObjCPU.Manufacturer & vbCrLf _
      & "接口规格: " & ObjCPU.SocketDesignation & vbCrLf _
      & "CPU 数量: " & ObjCPU.CpuStatus & vbCrLf _
      & "核心数量: " & ObjCPU.NumberOfCores & vbCrLf _
      & "线程数量: " & ObjCPU.NumberOfLogicalProcessors & vbCrLf _
      & "地址位宽: " & ObjCPU.AddressWidth & " Bit" & vbCrLf _
      & "数据位宽: " & ObjCPU.DataWidth & " Bit" & vbCrLf _
      & "CPU 电压: " & ObjCPU.CurrentVoltage / 10 & "V" & vbCrLf _
      & "外部频率: " & ObjCPU.ExtClock & " MHz" & vbCrLf _
      & "当前频率: " & OC & " MHz" & OCLC & vbCrLf _
      & "原始频率: " & MCS & " MHz" & vbCrLf _
      & "CPU 使用: " & ObjCPU.LoadPercentage & "%" & vbCrLf
 Next
 
  For Each objCache In Caches
     If objCache.MaxCacheSize > 0 Then
         Select Case objCache.Purpose
         Case "L1-Cache"
         CPUx = CPUx & "一级缓存: " & objCache.MaxCacheSize & "KB    (L1数据+L1缓存)" & vbCrLf
         Case "L2-Cache"
         CPUx = CPUx & "二级缓存: " & objCache.MaxCacheSize & " KB" & vbCrLf
         Case "L3-Cache"
         CPUx = CPUx & "三级缓存: " & objCache.MaxCacheSize & " KB" & vbCrLf
         End Select
     End If
 Next
 Set Caches = Nothing: Set CPUs = Nothing
 
 Memx = "————————————内存信息————————————" & vbCrLf
 Set Memorys = WMI.InstancesOf("Win32_PhysicalMemory")
 Set MemKY = WMI.InstancesOf("Win32_OperatingSystem")
 For Each aKY In MemKY
     ZL = aKY.TotalVisibleMemorySize 'TotalPhysicalMemory
     KY = aKY.FreePhysicalMemory
 Next
 Mems = 0: Memc = 0
 Types = Array("Unknown", "Other", "DRAM", "Synchronous DRAM", "Cache DRAM", "EDO", "EDRAM", "VRAM", "SRAM", "RAM", _
                "ROM", "Flash", "EEPROM", "FEPROM", "EPROM", "CDRAM", "3DRAM", "SDRAM", "SGRAM", "RDRAM", "DDR", "DDR2")
 For Each Mem In Memorys
     For I = 0 To UBound(Types)
         If Mem.MemoryType = I Then MemType = Types(I)
     Next
     For j = 0 To 6
         Select Case Mem.Tag
             Case "Physical Memory " & j
             Mems = Mems + (Mem.Capacity)
             Memx = Memx & "插槽" & Mem.DeviceLocator & ": " & Round(Mem.Capacity / 1048576) & " MB  " _
                 & MemType & "-" & Mem.Speed & "MHz" & " 数据带宽" & Mem.DataWidth & "Bit" & " 总带宽" & Mem.TotalWidth & "Bit" & vbCrLf
         End Select
     Next
 Next
 Memx = Memx _
      & "内存安装: " & Round(Mems / 1048576) & " MB " & vbCrLf _
      & "内存总量: " & Round(ZL / 1024) & " MB" & vbCrLf _
      & "内存可用: " & Round(KY / 1024) & " MB" & vbCrLf _
      & "内存使用率: " & FormatPercent((ZL - KY) / ZL) & vbCrLf
 Set Memorys = Nothing: Set MemKY = Nothing
 
 Vx = "————————————显卡信息————————————" & vbCrLf
 Set cVID = WMI.ExecQuery("SELECT DeviceID FROM Win32_VideoController")
 For Each oVID In cVID
     Set Video = WMI.ExecQuery("SELECT * FROM Win32_VideoController WHERE DeviceID='" & oVID.DeviceID & "'")
     For Each oVideo In Video
         Vx = Vx _
         & "显卡名称: " & oVideo.Name & vbCrLf _
         & "制造厂商: " & oVideo.AdapterCompatibility & vbCrLf _
         & "物理显存: " & Round(oVideo.AdapterRAM / 1048576) & " MB " & vbCrLf _
         & "显示模式: " & oVideo.CurrentHorizontalResolution & " X " _
                        & oVideo.CurrentVerticalResolution & " " _
                        & oVideo.CurrentBitsPerPixel & "Bit " _
                        & oVideo.CurrentRefreshRate + 1 & "Hz" & vbCrLf
     Next
 Next
 Set Video = Nothing: Set cVID = Nothing
 
 Dx = "————————————硬盘信息————————————" & vbCrLf
 Set IDE = WMI.ExecQuery("Select * from Win32_DiskDrive WHERE InterfaceType='IDE'")
 Set cPPP = WMI.ExecQuery("SELECT * FROM Win32_PerfRawData_PerfDisk_PhysicalDisk")
 For Each oIDE In IDE
     For I = 0 To IDE.Count
         Select Case oIDE.Index
             Case I
                For Each oPPP In cPPP
                    If InStr(oPPP.Name, I) Then vName = oPPP.Name
                Next
                Dx = Dx & "硬盘" & I & ":" & vbTab & oIDE.Caption & vbCrLf & vbTab & "固件版本: " & oIDE.FirmwareRevision & vbCrLf
                If CStr(Err.Number) <> 0 Then Dx = Dx & "硬盘" & I & ":" & vbTab & oIDE.Caption & vbCrLf
                Dx = Dx & vbTab & "标称容量: " & Round(oIDE.Size / 1000000000) & " GB" & vbTab & "实际容量: " & Round(oIDE.Size / 1073741824) & " GB" & vbCrLf _
                & vbTab & "柱面数: " & oIDE.TotalCylinders & vbTab & "磁头数: " & oIDE.TotalHeads & vbCrLf _
                & vbTab & "每道扇区数: " & oIDE.SectorsPerTrack & vbTab & "扇区大小: " & oIDE.BytesPerSector & vbCrLf _
                & vbTab & "总扇区数: " & oIDE.TotalSectors & vbCrLf & vbTab & "分区状态: " & vName & vbCrLf
                DevID = Replace(oIDE.DeviceID, "\", "\\")
                Set cDP = WMI.ExecQuery("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & DevID & """} WHERE AssocClass = Win32_DiskDriveToDiskPartition")
                For Each oDP In cDP
                  Set cLD = WMI.ExecQuery("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & oDP.DeviceID & """} WHERE AssocClass = Win32_LogicalDiskToPartition")
                    For Each oLD In cLD
                      Dx = Dx & vbTab & oLD.DeviceID & " " & Left(oLD.VolumeName & "         ", 11) & Left(oLD.FileSystem & "   ", 6) & "共:" _
                         & Right("    " & Round(oLD.Size / 1073741824, 1), 6) & " GB    可用:" _
                         & Right("    " & Round(oLD.FreeSpace / 1073741824, 1), 6) & " GB    已用:" _
                         & Right("    " & Round((oLD.Size - oLD.FreeSpace) / 1073741824, 1), 6) & " GB" & vbCrLf
                    Next
               Next
         End Select
     Next
 Next
 Set cLD = Nothing: Set cDP = Nothing: Set IDE = Nothing: Set cDP = Nothing: Set cPPP = Nothing
 
 Sx = "————————————声卡信息————————————" & vbCrLf
 Set cSD = WMI.ExecQuery("SELECT * FROM Win32_SoundDevice")
 For Each oSD In cSD
     Sx = Sx & "声卡名称: " & oSD.ProductName & vbCrLf
 Next
 Set cSD = Nothing
 Nx = "————————————网卡信息————————————" & vbCrLf
 Set cNet = WMI.ExecQuery("Select * from Win32_NetworkAdapter WHERE PhysicalAdapter ='TRUE'")
 For Each oNet In cNet
     If oNet.NetEnabled = True Then
        Nx = Nx & "网卡名称: " & oNet.Name & vbTab & "活跃状态" & vbCrLf
        Else
        Nx = Nx & "网卡名称: " & oNet.Name & vbTab & "空闲状态" & vbCrLf
     End If
     
 Next
 Set cNet = Nothing
 Set WMI = Nothing
 
     Set WS = CreateObject("WScript.Shell")
     Set Fso = CreateObject("Scripting.FileSystemObject")
     aFile = "C:\Hardware_Info.txt"
     Set HInfo = Fso.CreateTextFile(aFile, True)
     Dim strbody As String
     If Option1.Value = True Then
     strbody = strbody & "姓名: " & Text1.Text & vbCrLf
     Else
     strbody = strbody & "联系人: " & Text1.Text & vbCrLf
     End If
     strbody = strbody & "电话: " & Text2.Text & vbCrLf
     strbody = strbody & "地址: " & Text3.Text & vbCrLf
     If Option2.Value = True Then strbody = strbody & "单位名称: " & Text4.Text & vbCrLf
     strbody = strbody & OSx & BBx & CPUx & Memx & Vx & Sx & Nx & Dx & JZCSx & vbCrLf
     strbody = strbody & "BY: 算神  http://blog.lishewen.com/"
     HInfo.WriteLine strbody
     HInfo.Close
     'WS.Run Chr(34) & aFile & Chr(34)
 Set WS = Nothing: Set Fso = Nothing: Set HInfo = Nothing
 Form2.sendform Text1.Text & "的电脑配置", strbody
End Sub

Google开发者学院(中文版)正式上线

最近通过官方渠道得知,Google 开发者学院(中文版)已经正式上线!

Google 开发者学院提供了一系列在线课程,涵盖了各种不同的 Google 开发者工具和平台。此处的课程材料向各种技术级别的开发者提供了传统技术文档之外的基于课程的学习内容。请注意,这些课程的内容大部分是中文的!

考虑到互联网以及中国开发者的特点,Google 特别将这些课程的大多数内容翻译成中文,方便开发者们学习和阅读。从另一个角度来说,这反应了 Google 对中国开发者们的重视,希望能更加接近这些开发者们,让大家从此不再受到英文阅读能力的制约!

在网站上线后,已经收到了西班牙,日本,韩国等几个国家的开发者们的反馈,目前来自中国的反馈为0。由于 Google 开发者学院刚上线不久,在课程内容翻译的质量,准确度上可能仍需要调整,所以希望大家能向 Google 多提出一些意见和反馈。

我们不能仅停留在自己的层面上,走向世界不是空号,而是通过你的认真反馈,让 Google 了解中国开发者的声音,让他们重视中国的市场,做出更多有利于开发者进行学习,创业的事情。

在国外有种风格,中国人如果不发出声音,他们就会认为我们没问题,不重视我们,我们需要以一个 geng 积极的姿态去面对 Google 对中国开发者敞开的大门!

如果大家对课程有任何问题,可以点击该课程右上角的“有关此文档的反馈”按钮,将你们的问题向 Google 提出来。

摘取一段来自 Google 技术部门对中国开发者们说出的话:

要是中国的开发者们没有任何声音,Google 从事翻译的部门就会认为中国市场或中国的开发者们是无足轻重的、可能会认为以后就不必要提供中文的翻译的了。这对大家以后再国内阅读和学习这些材料,会是一个增加不方便的不利影响。一方面我们有不少开发者认为阅读英文的技术文档比较困难,另一方面当有了中文的文档提供了之后,又没有人说到底这些翻译是否有任何问题,会给从事翻译的人造成一种错觉,怀疑提供中文翻译是否有任何价值。 所以希望中国的开发者们能够发出自己的声音来。

中国开发者们要勇敢地走向世界,在国际上在任何有关自己利益的事情上要敢于发出我们自己的声音、要敢于去通过提出我们的意见去影响技术的发展!

微软关闭Silverlight官网,该技术逐渐被边缘化

微软今天关闭了 Silverlight.net 网站,现在访问该网站,会被转到 MSDN 的一个 Silverlight 专题页面

在新的页面中,你仍然可以找到一些 Silverlight 相关的内容,但不是全部。如果你之前已经收藏了一些 Silverlight.net 域下的网页,现在可能已经失效了。

此外,Silverlight 博客近一段时间发布的也都是一些与 Silverlight 无关的文章。

这些现象预示着 Silverlight 已经逐渐被边缘化,另一侧面也反映了微软内部团队之间的斗争。

“微软放弃 Silverlight”的传闻早在几年前就闹得沸沸扬扬,争论主要围绕 Silverlight 和 HTML5。HTML5 强大的功能,令人们看不到 Silverlight 的发展前景,人们一直在问微软 Silverlight 研发团队一个问题:如今浏览器已经支持 HTML5 <video>标签,在这样的环境下,Silverlight 将扮演何种角色。

当时微软官方认为 Silverlight 和 HTML 5 会同时存在,理由是 HTML5 还没有发展到足够强大,Silverlight 的媒体功能远超出 HTML 5 所能提供的功能,因此会把 Silverlight 作为移动、Web 和 PC 跨平台解决方案加以支持。但目前来看,微软极力在其 IE 浏览器中完善对 HTML5 的支持,已经逐渐将 Silverlight 边缘化。

在微软的移动领域布局中,Silverlight 功不可没,它曾是 WP7 的主要开发技术之一。但是现在微软力推 WP8,该系统和 WP7 拥有完全不同的核心,微软更倾向于开发者使用 HTML5 开发跨平台应用。

在 WP8 中,仍可以运行基于 Silverlight 的应用,但是你不能进一步开发,也不能开始构建一个新的 Silverlight 应用。

在 Silverlight 5 发布时,就有媒体预测,这将是 Silverlight 的最后一个版本。但是,Silverlight 主要绑定在 Windows 桌面和 IE,只要 Windows 一直保持操作系统的霸主地位,Silverlight 仍然会存在相当长的一段时间。

Node.js 究竟是什么?

简介

如果您听说过 Node,或者阅读过一些文章,宣称 Node 是多么多么的棒,那么您可能会想:“Node 究竟是什么东西?”尽管不是针对所有人的,但 Node 可能是某些人的正确选择。

为试图解释什么是 Node.js,本文探究了它能解决的问题,它如何工作,如何运行一个简单应用程序,最后,Node 何时是和何时不是一个好的解决方案。本文不涉及如何编写一个复杂的 Node 应用程序,也不是一份全面的 Node 教程。阅读本文应该有助于您决定是否应该学习 Node,以便将其用于您的业务。

Node 旨在解决什么问题?

Node 公开宣称的目标是 “旨在提供一种简单的构建可伸缩网络程序的方法”。当前的服务器程序有什么问题?我们来做个数学题。在 Java™ 和 PHP 这类语言中,每个连接都会生成一个新线程,每个新线程可能需要 2 MB 配套内存。在一个拥有 8 GB RAM 的系统上,理论上最大的并发连接数量是 4,000 个用户。随着您的客户端基础的增长,您希望您的 web 应用程序支持更多用户,这样,您必须添加更多服务器。当然,这会增加业务成本,尤其是服务器成本、运输成本和人工成本。除这些成本上升外,还有一个技术问题:用户可能针对每个请求使用不同的服务器,因此,任何共享资源都必须在所有服务器之间共享。例如,在 Java 中,静态变量和缓存需要在每个服务器上的 JVMs 之间共���。这就是整个 web 应用程序架构中的瓶颈:一个服务器能够处理的并发连接的最大数量。

Node 解决这个问题的方法是:更改连接连接到服务器的方式。每个连接都创建一个进程,该进程不需要配套内存块,而不是为每个连接生成一个新的 OS 线程(并向其分配一些配套内存)。Node 声称它绝不会死锁,因为它根本不允许使用锁,它不会直接阻塞 I/O 调用。Node 还宣称,运行它的服务器能支持数万个并发连接。事实上,Node 通过将整个系统中的瓶颈从最大连接数量更改到单个系统的流量来改变服务器面貌。

现在您有了一个能处理数万条并发连接的程序,那么您能通过 Node 实际构建什么呢?如果您有一个 web 应用程序需要处理这么多连接,那将是一件很 “恐怖” 的事!那是一种 “如果您有这个问题,那么它根本不是问题” 的问题。在回答上面的问题之前,我们先看看 Node 如何工作以及它被设计的如何运行。

Node 肯定不是什么

没错,Node 是一个服务器程序。但是,它肯定不 像 Apache 或 Tomcat。那些服务器是独立服务器产品,可以立即安装并部署应用程序。通过这些产品,您可以在一分钟内启动并运行一个服务器。Node 肯定不是这种产品。Apache 能添加一个 PHP 模块来允许开发人员创建动态 web 页,使用 Tomcat 的程序员能部署 JSPs 来创建动态 web 页。Node 肯定不是这种类型。

在 Node 的早期阶段(当前是 version 0.4.6),它还不是一个 “运行就绪” 的服务器程序,您还不能安装它,向其中放置文件,拥有一个功能齐全的 web 服务器。即使是要实现 web 服务器在安装完成后启动并运行这个基本功能,也还需要做大量工作。

Node 如何工作

Node 本身运行 V8 JavaScript。等等,服务器上的 JavaScript?没错,您没有看错。服务器端 JavaScript 是一个相对较新的概念,这个概念是大约两年前在 developerWorks 上讨论 Aptana Jaxer 产品时提到的(参见 参考资料)。尽管 Jaxer 一直没有真正流行,但这个理念本身并不是遥不可及的 — 为何不能在服务器上使用客户机上使用的编程语言?

什么使 V8?V8 JavaScript 引擎是 Google 用于他们的 Chrome 浏览器的底层 JavaScript 引擎。很少有人考虑 JavaScript 在客户机上实际做了些什么?实际上,JavaScript 引擎负责解释并执行代码。使用 V8,Google 创建了一个以 C++ 编写的超快解释器,该解释器拥有另一个独特特征;您可以下载该引擎并将其嵌入任何 应用程序。它不仅限于在一个浏览器中运行。因此,Node 实际上使用 Google 编写的 V8 JavaScript 引擎并将其重建为在服务器上使用。太完美了!既然已经有一个不错的解决方案可用,为何还要创建一种新语言呢?

事件驱动编程

许多程序员接受的教育使他们认为,面向对象编程是完美的编程设计,而对其他编程方法不屑一顾。Node 使用一个所谓的事件驱动编程模型。

清单 1. 客户端上使用 jQuery 的事件驱动编程

// jQuery code on the client-side showing how Event-Driven programming works
// When a button is pressed, an Event occurs - deal with it
// directly right here in an anonymous function, where all the
// necessary variables are present and can be referenced directly
$("#myButton").click(function(){
if ($("#myTextField").val() != $(this).val())
alert("Field must match button text");
});

实际上,服务器端和客户端没有任何区别。没错,这没有按钮点击操作,也没有向文本字段键入的操作,但在一个更高的层面上,事件正在 发生。一个连接被建立 — 事件!数据通过连接接收 — 事件!数据通过连接停止 — 事件!

为什么这种设置类型对 Node 很理想?JavaScript 是一种很棒的事件驱动编程语言,因为它允许匿名函数和闭包,更重要的是,任何写过代码的人都熟悉它的语法。事件发生时调用的回调函数可以在捕获事件处编写。这样,代码容易编写和维护,没有复杂的面向对象框架,没有接口,没有在上面架构任何内容的潜能。只需监听事件,编写一个回调函数,然后,事件驱动编程将照管好一切!

示例 Node 应用程序

最后,我们来看一些代码!让我们将讨论过的所有内容综合起来,创建我们的第一个 Node 应用程序。由于我们已经知道,Node 对于处理高流量应用程序很理想,我们就来创建一个非常简单的 web 应用程序 — 一个为实现最大速度而构建的应用程序。下面是 “老板” 交代的关于我们的样例应用程序的具体要求:创建一个随机数字生成器 RESTful API。这个应用程序应该接受一个输入:一个名为 “number” 的参数。然后,应用程序返回一个介于 0 和该参数之间的随机数字,并将生成的数字返回调用者。由于 “老板” 希望它成为一个广泛流行的应用程序,因此它应该能处理 50,000 个并发用户。我们来看看代码:

清单 2. Node 随机数字生成器

// these modules need to be imported in order to use them. 
// Node has several modules.  They are like any #include 
// or import statement in other languages 
var http = require("http"); 
var url = require("url"); 
// The most important line in any Node file.  This function 
// does the actual process of creating the server.  Technically, 
// Node tells the underlying operating system that whenever a 
// connection is made, this particular callback function should be 
// executed.  Since we're creating a web service with REST API, 
// we want an HTTP server, which requires the http variable 
// we created in the lines above. 
// Finally, you can see that the callback method receives a 'request' 
// and 'response' object automatically.  This should be familiar 
// to any PHP or Java programmer. 
http.createServer(function(request, response) { 
// The response needs to handle all the headers, and the return codes 
// These types of things are handled automatically in server programs 
// like Apache and Tomcat, but Node requires everything to be done yourself 
response.writeHead(200, {"Content-Type": "text/plain"}); 
// Here is some unique-looking code.  This is how Node retrives 
// parameters passed in from client requests.  The url module 
// handles all these functions.  The parse function 
// deconstructs the URL, and places the query key-values in the 
// query object.  We can find the value for the "number" key 
// by referencing it directly - the beauty of JavaScript. 
var params = url.parse(request.url, true).query; 
var input = params.number; 
// These are the generic JavaScript methods that will create 
// our random number that gets passed back to the caller 
var numInput = new Number(input); 
var numOutput = new Number(Math.random() * numInput).toFixed(0); 
// Write the random number to response 
response.write(numOutput); 
// Node requires us to explicitly end this connection.  This is because 
// Node allows you to keep a connection open and pass data back and forth, 
// though that advanced topic isn't discussed in this article. 
response.end(); 
// When we create the server, we have to explicitly connect the HTTP server to 
// a port.  Standard HTTP port is 80, so we'll connect it to that one. 
}).listen(80); 
// Output a String to the console once the server starts up, letting us know everything 
// starts up correctly 
console.log("Random Number Generator Running...");

启动应用程序

将上面的代码放到一个名为 “random.js” 的文件中。现在,要启动这个应用程序并运行它(进而创建 HTTP 服务器并监听端口 80 上的连接),只需在您的命令提示中输入以下命令:% node random.js。下面是服务器已经启动并运行时它看起来的样子:

root@ubuntu:/home/moila/ws/mike# node random.js 
Random Number Generator Running... 

访问应用程序

应用程序已经启动并运行。Node 正在监听任何连接,我们来测试一下。由于我们创建了一个简单的 RESTful API,我们可以使用我们的 web 浏览器来访问这个应用程序。键入以下地址(确保您完成了上面的步骤):http://localhost/?number=27。

您的浏览器窗口将更改到一个介于 0 到 27 之间的随机数字。单击浏览器上的 “重新载入” 按钮,将得到另一个随机数字。就是这样,这就是您的第一个 Node 应用程序!

Node 对什么有好处?

到此为止,应该能够回答 “Node 是什么” 这个问题了,但您可能还不清楚什么时候应该使用它。这是一个需要提出的重要问题,因为 Node 对有一些东西有好处,但相反,对另一些东西而言,目前 Node 可能不是一个好的解决方案。您需要小心决定何时使用 Node,因为在错误的情况下使用它可能会导致一个多余编码的 LOT。

它对什么有好处?

正如您此前所看到的,Node 非常适合以下情况:您预计可能有很高的流量,而在响应客户端之前服务器端逻辑和处理所需不一定是巨大的。Node 表现出众的典型示例包括:

RESTful API

提供 RESTful API 的 web 服务接收几个参数,解析它们,组合一个响应,并返回一个响应(通常是较少的文本)给用户。这是适合 Node 的理想情况,因为您可以构建它来处理数万条连接。它还不需要大量逻辑;它只是从一个数据库查找一些值并组合一个响应。由于响应是少量文本,入站请求时少量文本,因此流量不高,一台机器甚至也可以处理最繁忙的公司的 API 需求。

Twitter 队列

想像一下像 Twitter 这样的公司,它必须接收 tweets 并将其写入一个数据库。实际上,每秒几乎有数千条 tweets 达到,数据库不可能及时处理高峰时段需要的写入数量。Node 成为这个问题的解决方案的重要一环。如您所见,Node 能处理数万条入站 tweets。它能迅速轻松地将它们写入一个内存排队机制(例如 memcached),另一个单独进程可以从那里将它们写入数据库。Node 在这里的角色是迅速收集 tweet 并将这个信息传递给另一个负责写入的进程。想象一下另一种设计 — 一个常规 PHP 服务器自己试图处理对数据库的写入 — 每个 tweet 将在写入数据库时导致一个短暂的延迟,这是因为数据库调用正在阻塞通道。由于数据库延迟,一台这样设计的机器每秒可能只能处理 2000 条入站 tweets。每秒 100 万条 tweets 需要 500 个服务器。相反,Node 能处理每个连接而不会阻塞通道,从而能捕获尽可能多的 tweets。一个能处理 50,000 条 tweets 的 Node 机器只需要 20 个服务器。

映像文件服务器

一个拥有大型分布式网站的公司(比如 Facebook 或 Flickr)可能会决定将所有机器只用于服务映像。Node 将是这个问题的一个不错的解决方案,因为该公司能使用它编写一个简单的文件检索器,然后处理数万条连接。Node 将查找映像文件,返回文件或一个 404 错误,然后什么也不用做。这种设置将允许这类分布式网站减少它们服务映像、.js 和 .css 文件等静态文件所需的服务器数量。

它对什么有坏处?

当然,在某些情况下,Node 并非理想选择。下面是 Node 不擅长的领域:

动态创建的页

目前,Node 没有提供一种默认方法来创建动态页。例如,使用 JavaServer Pages (JSP) 技术时,可以创建一个在这样的 JSP 代码段中包含循环的 index.jsp 页。Node 不支持这类动态的、HTML 驱动的页面。同样,Node 不太适合作为 Apache 和 Tomcat 这样的网页服务器。因此,如果您想在 Node 中提供这样一个服务器端解决方案,必须自己编写整个解决方案。PHP 程序员不想在每次部署 web 应用程序时都编写一个针对 Apache 的 PHP 转换器,当目前为止,这正是 Node 要求您做的。

关系数据库重型应用程序

Node 的目的是快速、异步和非阻塞。数据库并不一定分享这些目标。它们是同步和阻塞的,因为读写时对数据库的调用在结果生成之前将一直阻塞通道。因此,一个每个请求都需要大量数据库调用、大量读取、大量写入的 web 应用程序非常不适合 Node,这是因为关系数据库本身就能抵销 Node 的众多优势。(新的 NoSQL 数据库更适合 Node,不过那完全是另一个主题了。)

结束语

问题是 “什么是 Node.js?” 应该已经得到解答。阅读本文之后,您应该能通过几个清晰简洁的句子回答这个问题。如果这样,那么您已经走到了许多编码员和程序员的前面。我和许多人都谈论过 Node,但它们对 Node 究竟是什么一直很迷惑。可以理解,他们具有的是 Apache 的思维方式 — 服务器是一个应用程序,将 HTML 文件放入其中,一切就会正常运转。而 Node 是目的驱动的。它是一个软件程序,使用 JavaScript 来允许程序员轻松快速地创建快速、可伸缩的 web 服务器。Apache 是运行就绪的,而 Node 是编码就绪的。

Node 完成了它提供高度可伸缩服务器的目标。它并不分配一个 “每个连接一个线程” 模型,而是使用一个 “每个连接一个流程” 模型,只创建每个连接需要的内存。它使用 Google 的一个非常快速的 JavaScript 引擎:V8 引擎。它使用一个事件驱动设计来保持代码最小且易于阅读。所有这些因素促成了 Node 的理想目标 — 编写一个高度可伸缩的解决方案变得比较容易。

与理解 Node 是 什么同样重要的是,理解它不是 什么。Node 并不是 Apache 的一个替代品,后者旨在使 PHP web 应用程序更容易伸缩。事实确实如此。在 Node 的这个初始阶段,大量程序员使用它的可能性不大,但在它能发挥作用的场景中,它的表现非常好。

将来应该期望从 Node 得到什么呢?这也许是本文引出的最重要的问题。既然您知道了它现在的作用,您应该会想知道它下一步将做什么。在接下来的一年中,我期待着 Node 提供与现有的第三方支持库更好地集成。现在,许多第三方程序员已经研发了用于 Node 的插件,包括添加文件服务器支持和 MySQL 支持。希望 Node 开始将它们集成到其核心功能中。最后,我还希望 Node 支持某种动态页面模块,这样,您就可以在 HTML 文件中执行在 PHP 和 JSP(也许是一个 NSP,一个 Node 服务器页)中所做的操作。最后,希望有一天会出现一个 “部署就绪” 的 Node 服务器,可以下载和安装,只需将您的 HTML 文件放到其中,就像使用 Apache 或 Tomcat 那样。Node 现在还处于初始阶段,但它发展得很快,可能不久就会出现在您的视野中。

新浪微博Win8 APP启动秒退Bug的分析

自从更新Win8 RTM后,应用程序商店里面的新浪客户端就不能正常运行,多次卸载重装都不行,于是祭出ILSpy把那个APP反编译了。

经过多次调试发现是以下这段代码报错

private async void GetDeviceInfo()
{
    string[] array = new string[]
    {
        "System.Devices.ModelName",
        "System.Devices.Manufacturer"
    };
    string text = "System.Devices.LocalMachine:=System.StructuredQueryType.Boolean#True";
    PnpObjectCollection pnpObjectCollection = await PnpObject.FindAllAsync(PnpObjectType.DeviceContainer, array, text);
    if (pnpObjectCollection != null && ((IReadOnlyCollection<PnpObject>)pnpObjectCollection).Count > 0)
    {
        PnpObject pnpObject = ((IReadOnlyList<PnpObject>)pnpObjectCollection)[0];
        WeiboConstant.DeviceModel = pnpObject.get_Properties()[array[0]].ToString();
        WeiboConstant.DeviceManufacturer = pnpObject.get_Properties()[array[1]].ToString();
    }
    PackageVersion version = Package.Current.Id.Version;
    WeiboConstant.UAValue = string.Format("{0}__weibo__{1}.{2}.{3}__win8pad", new object[]
    {
        WeiboConstant.DeviceModel,
        version.Major,
        version.Minor,
        version.Build
    });
}

报错的地方为:

WeiboConstant.DeviceModel = pnpObject.get_Properties()[array[0]].ToString();
WeiboConstant.DeviceManufacturer = pnpObject.get_Properties()[array[1]].ToString();

这两句抛出了没有处理的null异常

原因很简单,由于笔者用得不是品牌电脑,所以没有制造商信息,故属性值为null,然后代码把null值ToString()的时候就会抛出null异常

这个在微软官方论坛上得到了证实(http://social.msdn.microsoft.com/Forums/zh-CN/metroappzhcn/thread/c7397740-4b30-4324-bf95-3c2bf84fc60d

笔者和新浪微博Win8 APP的其中一位开发人员取得了联系,反馈了这个Bug并拿到了修正Bug后的离线包,已经正常用上了眨眼

离线包安装需要最少开发者越狱,和一定的系统知识这里我就先不发了,各位看官还是等应用市场更新吧

另:目测 WeiboConstant.DeviceModel 应该就是日后Win8品牌机尾巴识别用的了,先在这备注一下,日后修改尾巴的时候可以用到吐舌鬼脸

下载托管在Google App Engine平台的Python程序源代码

     如果保存在本地的GAE Python代码损坏、或者不小心删掉、或者代码改动以后想恢复以前的版本,我们可以直接把当前运行在GAE上的程序代码下载到本地。使用Google App Engine SDK提供的appcfg.py工具即可,方法为在CMD命令行窗口运行如下命令:

appcfg.py download_app -A <application-id> -V <application-version> <output-dir>

      例如,如果你的GAE程序ID为myGAE,版本号为1,希望代码保存在c:\myGAE目录,运行如下命令即可:

appcfg.py download_app -A lswGAE -V 1 c:\lswGAE

      注意运行命令之前先要进入GAE SDK的目录下,否则appcfg.py不会被正确执行。如果运行正常就会出现Fetching file list… 的提示,如下图所示。


然后按照提示输入账号密码即可。需要注意的是,下载程序连接到appengine.google.com,众所周知,这个地址被墙。所以如果你没有VPN或者代理,请不要尝试上面的操作,因为一定会失败…

MEF for Windows 8 Metro和TPL Data Flow迁移到NuGet

微软决定从 .NET 4.5 框架中删除 MEF for Windows 8 Metro 和 TPL Data Flow。 取而代之的是,他们会作为 NuGet 程序包提供,从而以后做出的改进可以在完整的 .NET 发布周期之外发布。

这个决定延续了微软开发部门中的总体趋势,他们要摆脱庞大的开发周期。 很好的例子就是 ASP.NET MVC。 从 2009 年开始,它已经发布了三个主要版本,并且马上要发布第四个版本。 相比之下,ASP.NET WebForms 只发布了一个版本。 尽管 WebForms 的下一版本包含了大量改进,应该和 MVC 做出改进的同时发布,但是微软还是要等到 Visual Studio 2012 和 .NET 4.5 都就绪了之后再发布。

更复杂的例子是实体框架。 这种产品的核心还是与 .NET 的发布周期绑定在一起。 然而,很多重要的特性,像“代码优先”,也使用 NuGet 在其之外发布了。

使用 NuGet 来发布有很大好处,这让程序库可以使用最初发布时所没有使用的功能。 对于 TPL Dataflow,人们认为它是服务端的应用程序。 然而,现在它“在各处都可以得到支持,包括桌面、服务器和 Metro 样式的 .NET 应用程序”。

好吧,上面的举例可能不完全精确。 TPL Dataflow 的 NuGet 版本包含了一种许可限制,声称它只能在 Windows 的计算机上使用。 所以,即便是兼容 Mono,你也无法在 Mono 项目中使用它。

另外,MEF 是开源的项目。 所以,尽管 TPL Dataflow 是可以理解的,但是 MEF for web and Metro style 也有同样的平台限制就有些奇怪了。 如果在非发布的候选版本中不改变许可,我们就真的会感到奇怪了。

使用Visual Studio 2010与2012工作于相同项目

过去,当开发人员将一个 Visual Studio 项目迁移至新版本时,该项目将没法在任何一个早期版本中使用。Visual Studio 2012 RC 推出了一个叫做“项目往返切换(project round-tripping)“的特性,现在团队可以让项目在 Visual Studio 2010 和 2012 之间往返工作了。

Visual Studio 2010 SP1 包含了支持项目往返切换的框架。据 Visual Studio 博客上说,

在 Visual Studio 2010 中,我们启用了完整的多目标支持,用于服务 Visual Studio 与 .NET 运行时之间的一对一支持。它可以让 Visual Studio 2010 中创建的项目定向到老版本的 .NET Framework,这推进了我们启用 Visual Studio 项目在不同版本之间的往返切换的脚步。在 Visual Studio 11 中,我们自然而然地迈出了另一步,正确处理不同环境下的项目。

在使用往返切换功能之前,需要了解的重要事项是此类项目仅向后兼容 Visual Studio 2010 SP1,并且应用程序必须目标定向为 .NET Framework 2-4。兼容性同样根据项目类型的不同而有所不同,有一些项目是完全不可行的。(微软已经提供了一份包含兼容性细节的清单。)

项目行为

微软声明说,大部分项目在 Visual Studio 2010 SP1 与 2012 中的行为一致,从而往返切换没有问题。对于在构建路径上使用硬编码版本号的项目,它们中的版本号会自动更新为变量进行替代,所有的改动就仅限于此。应当可以无缝进行往返切换的项目类型有:Windows Forms、Sharepoint、WPF 以及大部分 SQL Server 项目。

其他项目也可以自动升级用于支持往返切换。Visual Studio 2012 在项目打开时,会显示一个”检查项目及解决方案改动“的对话框并显示影响的条目。用户可以在升级发生前检查提到的改动,之后过程会创建一个备份。一旦 Visual Studio 2012 执行修改后,项目就可以同时在 2012 与 2010 SP1 中使用了。Silverlight 4 与5、Blend 和 Visual Studio 2010 Web 项目也属于此类。

特定类型的项目在升级后的行为与此前的 Visual Studio 一样:一旦它们被转换后,将不能在任何其他版本的 Visual Studio 中使用。这些项目类型包括F#、LightSwitch 以及 SQL Server LocalDB。

不在此列的项目

Windows Phone、Windows Mobile、Windows Azure 云工具、BizTalk 2010 R2 以及 Visual Studio 安装程序(*.msi)项目没法在 Visual Studio 2012 RC 中使用。微软对是否在最终版本中为上述类型的项目提供往返切换支持尚未说明。对于安装程序项目,微软鼓励开发人员使用 InstallShield Limited Edition for Visual Studio 进行替代。

ASP.NET Web API现使用Json.NET

ASP.NET Web API发布候选版获得了若干增强,如将Json.NET作为默认的序列化器,可测试性更好的Http消息处理器,以及IAPIExplorer API等等。

特别一提的是,Json.NET目前成为了Web API默认的序列化器,这意味着我们不再需要切换默认实现——例如,为了能够使用日期(Json.NET 4.5默认使用ISO 8601日期格式)。结果,多余的System.Json.dll已经被移除。正如微软所说:

Json.NET为一个现代Web框架提供了灵活性与性能。

HttpClient现在派生于一个新的HttpMessageInvoker类。我们可以使用后者对Http消息处理器进行单元测试,而不再需要直接使用更为重量级的前者。此外,IAPIExplorer API现已加入到发行版本中。完整的改动可以查看发行说明

ASP.NET Web API是微软用于构建RESTful Web服务的WCF替代方案。RC版还发布了其他ASP.NET Web栈组件,如ASP.NET web pages 2ASP.NET MVC 4