当前位置: 首页 > 编程日记 > 正文

在ASP.NET中跟踪和恢复大文件下载

在Web应用程序中处理大文件下载的问题一直出了名的困难,因此对于大多数站点来说,如果用户的下载被中断了,它们只能说悲哀降临到用户的身上了。但是我们现在不必这样了,因为你可以使自己的ASP.NET应用程序有能力支持可恢复(继续)的大文件下载。使用本文提供的方法的时候,你可以跟踪下载的过程,这样你就可以处理动态建立的文件--而且要达到这个目标根本不需要旧式的ISAPI动态链接库和非受控的(unmanaged)C++代码。

  为客户端提供从互联网上下载文件的服务最容易了,对吗?仅仅只需要把可下载的文件复制到你的Web应用程序目录中,发布链接并让IIS完成所有相关的工作。但是,文件服务不应该比脖子上的疼痛还要多(还要麻烦),你不希望整个世界都能访问自己的数据,你不希望服务器被数百个静态文件塞满了,你甚至于希望下载临时文件--只有当客户端开始下载后的空闲时间才建立这些文件。

  不幸的是,使用IIS对下载请求的默认的响应是不可能达到这些效果的。因此在一般情况下,为了获得对下载过程的控制权,开发者需要链接到一个定制的.aspx页面,在这个页面中它们检查用户凭证(credential)、建立可以下载的文件并使用下面的代码把该文件推送给客户端:

Response.WriteFile
Response.End()


  而这就是出现真正麻烦的地方。

  有什么问题?

  WriteFile方法看起来非常完美,它使文件的二进制数据流向客户端。但是直到最近我们才知道,WriteFile方法是一个出名的内存占用狂,它把整个文件载入服务器的RAM中来提供服务(实际上它甚至于会占用文件两倍大小的空间)。对于大文件,这会引起服务内存问题,并且可能重复ASP.NET过程。但是在2004年6月微软发布了一个补丁解决了这个问题。这个补丁现在是.NET Framework 1.1补丁包(SP1)的一部分。

  这个补丁引入了TransmitFile方法,它把一个磁盘文件读入到较小的内存缓冲区之后就开始传输该文件。尽管这个方案解决了内存和循环的问题,但是它仍然不能令人满意。你不能控制响应的生命周期。你无法知道下载是否正确地完成了,你没有办法知道下载是否被中断了,并且(如果你建立了临时文件)你也不知道是否应该、以及什么时候可以删除这些文件。更糟的是,如果下载的确失败了,TransmitFile方法又从客户端下次尝试的文件头部开始下载。

  其中一种可能的解决方案--实现后台智能传输服务(BITS)对于多数站点来说是不可行的,因为这会毁掉维持客户端浏览器操作系统独立性而作出的努力。

  令人满意的解决方案的基础还是来自微软用于解决WriteFile引起的内存混乱问题的第一次尝试(见知识库文章812406)。那篇文章演示了智能的大块数据下载过程,它从文件流中读取数据。在服务器把字节块发送给客户端之前,它使用Response.IsClientConnected属性检查客户端是否仍然保持着连接。如果仍然保持连接,它就继续发送流字节,否则就停止,以防止服务器发送不必要的数据。
这就是我们采用的方法,特别是在下载临时文件的时候。在IsClientConnected返回False的情况下,你就知道下载过程被中断了,你应该保存文件;反之,当这个过程成功完成的时候,你就删除临时文件。此外,为了恢复中断了的下载,你需要做的工作是从上次下载尝试过程中客户端连接失败的文件点开始下载。

  HTTP协议和头信息(Header)支持

  HTTP协议支持可以用于处理被中断下载的头信息。使用少量的HTTP头信息,你可以增强自己的下载过程,使它完全遵循HTTP协议规范。这个规范与ranges一起提供恢复被中断的下载所需要的一切信息。

  下面是它的工作方式。首先,如果服务器支持客户端断点续传,它就在初始的响应中发送Accept-Ranges头信息。服务器还发送一个实体标签(entity tag)头信息(ETag),它包含一个唯一的标识字符串。

  下面的代码显示了IIS发送给客户端的用于响应一个初始下载请求的一些头信息,它向客户端传递了被请求的文件的详细信息。

HTTP/1.1 200 OK
Connection: close
Date: Tue, 19 Oct 2004 15:11:23 GMT
Accept-Ranges: bytes
Last-Modified: Sun, 26 Sep 2004 15:52:45 GMT
ETag: "47febb2cfd76c41:2062"
Cache-Control: private
Content-Type: application/x-zip-compressed
Content-Length: 2844011


  在接收这些头信息之后,如果下载被中断了,IE浏览器在后来的下载请求中会把Etag值和Range头信息发送回服务器。下面的代码显示了尝试恢复被中断下载时IE发送给服务器的一些头信息。

GET http://192.168.100.100/download.zip HTTP/1.0
Range: bytes=822603-
Unless-Modified-Since: Sun, 26 Sep 2004 15:52:45 GMT
If-Range: "47febb2cfd76c41:2062"


  这些头信息表明IE缓存了IIS提供的实体标签,并在If-Range头信息中把它发送回服务器了,这是确保下载从准确相同的文件恢复的一种途径。不幸的是,并非所有的浏览器的工作方式都相同。客户端发送的用于验证文件的其它HTTP头信息可能是If-Match、If-Unmodified-Since或者Unless-Modified-Since。很明显,该规范对于客户端软件必须支持哪些头信息,或者必须使用哪些头信息没有明确的规定。因此,有些客户端根本就没有使用头信息,而IE只使用If-Range和Unless-Modified-Since。你最好用代码检查这些信息。采用这种方式的时候,你的应用程序可以在非常高的层次遵循HTTP规范,并可以使用多种浏览器。Range头信息指明了被请求的字节范围--在例子中它是服务器应该恢复文件流的起始点。

  当IIS接收到恢复下载的请求类型时,它发回包含下面的头信息的响应信息:

HTTP/1.1 206 Partial Content
Content-Range: bytes 822603-2844010/2844011
Accept-Ranges: bytes
Last-Modified: Sun, 26 Sep 2004 15:52:45 GMT
ETag: "47febb2cfd76c41:2062"
Cache-Control: private
Content-Type: application/x-zip-compressed
Content-Length: 2021408


  请注意上面的代码与最初的下载请求的HTTP响应有点差别--恢复下载的请求是206而最初下载的请求是200。这表明通过线路传递进来的内容是部分文件。这一次Content-Range头信息指出了被传递字节的精确数量和位置。

  IE对于这些头信息是很挑剔的。如果最初的响应没有包含Etag头信息,IE永远不会尝试恢复下载。我测试过的其它客户端不使用ETag头信息,它们简单得依赖于文件名、请求范围,并使用Last-Modified头信息(如果它们试图验证该文件)。

  深入了解HTTP协议

  前面的部分中显示的头信息对于使恢复下载的解决方案运行来说是足够的,但是它没有完全覆盖HTTP规范。

  在单个请求中,Range头信息可以询问多个范围,这种特性称为"多部分范围(multipart ranges)"。请不要与分段下载(segmented downloading)混淆,几乎所有的下载工具都使用分段下载来提高下载速度。这些工具声称通过打开两个或多个并发的连接(每个连接请求文件的不同范围)提高了下载速度。

  多部分范围的想法并没有开启多个连接,但是它可以使客户端软件可以在单个请求/响应周期中请求某个文件的最前面的十个和最后面的十个字节。

  诚实地说,我从来都没有找到使用这种特性软件片断。但是我拒绝在代码声明中写入"它并不是完全的HTTP兼容的"。略去这个特性必定会触犯墨菲法则(Murphy's Law)。无论如何,多部分范围还是被用于电子邮件传输中,把头信息、普通文本和附件分开。

示例代码

  我们知道了客户端和服务器如何交换头信息以保证可恢复的下载,把这些知识与文件块流的思想结合起来,你就可以给自己的ASP.NET应用程序增加可靠的下载管理能力了。

  获取下载过程的控制权的方法是从客户端截取下载请求、读取头信息并适当地响应。在.NET之前,你必须编写ISAPI(Internet服务器API)应用程序来实现这种功能,但是.NET框架组件提供了一个IHttpHandler接口,在类中实现的时候,它允许你仅仅使用.NET代码就能够截取和处理请求。这意味着你的应用程序对于下载过程有完全控制权和响应性,再也不会涉及或使用IIS的自动化函数。

  示例代码在HttpHandler.vb文件中包含了一个自定义的HttpHandler类(ZIPHandler)。ZipHandler实现了IhttpHandler接口,并且处理对所有.zip文件的请求。

  为了测试示例代码,你需要在IIS中建立一个新的虚拟目录,并把源文件复制到那儿。在该目录中建立一个叫做download.zip的文件(请注意IIS和ASP.NET不能处理大于2GB的下载,因此要确保你的文件没有超过该限制)。配置你的IIS虚拟目录,通过aspnet_isapi.dll映射.zip扩展名。

  HttpHandler类:ZIPHandler

  在ASP.NET中映射了.zip扩展名之后,客户端每次向服务器请求.zip文件的时候,IIS调用ZipHandler类的ProcessRequest方法(见下载代码)。

  ProcessRequest方法首先建立自定义的FileInformation类(见下载代码)的一个实例,它封装了下载的状态(例如进行中、被中断了等等)。示例把download.zip示例文件的路径硬编码到代码中了。如果把这段代码应用于你自己的应用程序,需要修改它来打开被请求的文件。

' 使用objRequest检测请求了哪个文件,用该文件打开objFile。
' 例如objFile = New Download.FileInformation(<完整文件名>)
objFile = New Download.FileInformation( _
objContext.Server.MapPath("~/download.zip"))


  接下来,程序使用描述的HTTP头信息(如果请求提供了头信息)执行一系列的验证检查。它把每种检查都封装在小型私有函数中,如果验证成功的话就返回True。如果某个验证检查失败了,响应会立即终止,并发送适当的StatusCode值。

If Not objRequest.HttpMethod.Equals(HTTP_METHOD_GET) Or Not
objRequest.HttpMethod.Equals(HTTP_METHOD_HEAD) Then
 ' 目前只支持GET和HEAD方法
 objResponse.StatusCode = 501 ' 没有执行
ElseIf Not objFile.Exists Then
 ' 无法找到被请求的文件
 objResponse.StatusCode = 404 ' 没有找到
ElseIf objFile.Length > Int32.MaxValue Then
 ' 文件太大了
 objResponse.StatusCode = 413 ' 请求实体太大
ElseIf Not ParseRequestHeaderRange(objRequest, alRequestedRangesBegin, alRequestedRangesend, _
objFile.Length, bIsRangeRequest) Then
 ' Range请求中包含无用的实体
 objResponse.StatusCode = 400 ' 无用的请求
ElseIf Not CheckIfModifiedSince(objRequest,objFile) Then
 ' 实体没有被修改过
 objResponse.StatusCode = 304 ' 没有被修改过
ElseIf Not CheckIfUnmodifiedSince(objRequest,objFile) Then
 ' 实体在上次被请求的日期之后被修改过
 objResponse.StatusCode = 412 ' 预处理失败
ElseIf Not CheckIfMatch(objRequest, objFile) Then
 ' 实体与请求不匹配
 objResponse.StatusCode = 412 ' 预处理失败
ElseIf Not CheckIfNoneMatch(objRequest, objResponse,objFile) Then
 ' 实体的确与none-match请求匹配。
 ' 响应代码位于CheckIfNoneMatch函数中
Else
 ' 初步检查成功


  这些初步检查的函数中的ParseRequestHeaderRange(见下载代码)检查客户端是否请求了文件范围(这意味着是一个局部下载)。如果被请求的范围是无效的(无效范围指超越文件大小或包含不合理数字的范围数值),该方法把bIsRangeRequest设置为True。如果请求了范围,CheckIfRange方法会验证IfRange头信息。

  如果被请求的范围是有效的,代码会计算响应信息的大小。如果客户端请求了多个范围,响应信息大小的数值会包含多部分头部信息长度的数值。

  如果不能确定某个发送的头部信息值,程序将把这个下载请求作为最初请求而不是部分下载来处理,从文件的顶部开始发送一个新的下载流。

If bIsRangeRequest AndAlso CheckIfRange(objRequest, objFile) Then
 ' 这是范围请求
 ' 如果Range数组包含多个实体,它还是一个多部分范围请求
 bMultipart = CBool(alRequestedRangesBegin.GetUpperBound(0)>0)
 ' 进入每个范围来获取整个响应长度
 For iLoop = alRequestedRangesBegin.GetLowerBound(0) To alRequestedRangesBegin.GetUpperBound(0)
  ' 内容的长度(这个范围的)
  iResponseContentLength += Convert.ToInt32(alRequestedRangesend( _
iLoop) - alRequestedRangesBegin(iLoop)) + 1
  If bMultipart Then
   ' 如果是多部分范围请求,计算出将发送的中间头信息的长度
   iResponseContentLength += MULTIPART_BOUNDARY.Length
   iResponseContentLength += objFile.ContentType.Length
   iResponseContentLength += alRequestedRangesBegin(iLoop).ToString.Length
   iResponseContentLength += alRequestedRangesend(iLoop).ToString.Length
   iResponseContentLength += objFile.Length.ToString.Length
   ' 49是多部分下载中换行和其它必要的字符的长度
   iResponseContentLength += 49
  End If
 Next iLoop

 If bMultipart Then
  ' 如果是多部分范围请求,
  ' 我们还必须计算出将发送的最后一个中间头信息的长度
  iResponseContentLength +=MULTIPART_BOUNDARY.Length
  ' 8 是破折号和换行符的长度
  iResponseContentLength += 8
 Else
  ' 不是多部分下载,因此我们必须说明初始HTTP头信息的响应范围
  objResponse.AppendHeader( HTTP_HEADER_CONTENT_RANGE, "bytes " & _
  alRequestedRangesBegin(0).ToString & "-" & _
  alRequestedRangesend(0).ToString & "/" & _
  objFile.Length.ToString)
  'End If
  ' 范围响应
  objResponse.StatusCode = 206 ' 局部响应
 Else
  ' 这不是范围请求,或者被请求的范围实体ID与当前的实体ID不匹配,
  ' 因此开始新的下载
  ' 指明文件完成部分的大小等于内容的长度
  iResponseContentLength =Convert.ToInt32(objFile.Length)
  ' 返回正常的OK状态
  objResponse.StatusCode = 200
 End If
 ' 接下来服务器必须发送几个重要的响应头信息,例如内容长度、Etag、和文件的内容类型:
 ' 把内容长度写入响应
 objResponse.AppendHeader( HTTP_HEADER_CONTENT_LENGTH,iResponseContentLength.ToString)
 ' 把最后修改日期写入响应
 objResponse.AppendHeader( HTTP_HEADER_LAST_MODIFIED,objFile.LastWriteTimeUTC.ToString("r"))
 ' 告诉客户端软件我们接受了范围请求
 objResponse.AppendHeader( HTTP_HEADER_ACCEPT_RANGES,HTTP_HEADER_ACCEPT_RANGES_BYTES)
 ' 把文件的实体标签写入响应(用引号括起来)
 objResponse.AppendHeader(HTTP_HEADER_ENTITY_TAG, """" & objFile.EntityTag & """")
 ' 把内容类型写入响应
 If bMultipart Then
  ' 多部分消息有这种特殊的类型
  ' 在例子中文件实际的mime类型在以后才写入响应
  objResponse.ContentType = MULTIPART_CONTENTTYPE
 Else
  ' 单个部分消息拥有的文件内容类型
  objResponse.ContentType = objFile.ContentType
End If



  下载所需要的一切都准备好了,可以开始下载文件了。你将使用FileStream对象从文件中读取字节块。把FileInformation实例objFile的State属性设置为fsDownloadInProgress。只要客户端保持连接,服务器就从文件中读取字节块并发送给客户端。对于多部分下载,这段代码会发送特定的头信息。如果客户端中断连接,服务器就把文件状态设置为fsDownloadBroken。如果服务器完成了被请求范围的发送过程,它会把状态设置为fsDownloadFinished(见下载代码)。

FileInformation辅助类

  在ZIPHandler部分中你会发现,FileInformation是一个辅助类,它封装了下载状态信息(例如下载中、中断等等)。

  为了建立FileInformation的实例,你需要把被请求文件的路径传递给该类的构造函数:

Public Sub New(ByVal sPath As String)
 m_objFile = New System.IO.FileInfo(sPath)
End Sub


  FileInformation使用System.IO.FileInfo对象来获取文件的信息,这些信息是作为该对象的属性暴露的(例如文件是否存在、文件全名、大小等等)。这个类还暴露了一个DownloadState枚举,它描述了下载请求的多种状态:

Enum DownloadState
 ' Clear:没有下载过程,文件可能在维护
 fsClear = 1
 ' Locked:动态建立的文件不能被更改
 fsLocked = 2
 ' In Progress:文件被锁定了,下载过程正在进行
 fsDownloadInProgress = 6
 ' Broken:文件被锁定了,下载过程正在进行,但是被取消了
 fsDownloadBroken = 10
 ' Finished:文件被锁定了,下载过程完成了
 fsDownloadFinished = 18
End Enum


  FileInformation还提供了EntityTag属性值。示例代码中的这个值是硬编码的,这是由于示例代码只使用了一个下载文件,并且该文件不会被改变,但是对于实际应用程序来说,你会提供多个文件,甚至于动态地建立文件,你的代码必须为每个文件提供一个唯一的EntityTag值。此外,每次改变或修改该文件的时候,这个值也必须改变。这使客户端软件能够验证它们已经下载的字节块是否仍然是最新的。下面是示例代码中返回硬编码EntityTag值的部分:

Public ReadOnly Property EntityTag() As String
 ' EntityTag用于对客户端的初始(200)响应,以及来自客户端的恢复请求
 Get
  ' 为文件建立唯一的字符串。
  ' 注意,只要文件没有发生改变,该唯一码就必须保留。
  ' 但是,如果文件的确改变了或者被修改了,这个码必须改变。
  Return "MyExampleFileID"
 End Get
End Property


  一个简单的和大致足够安全的EntityTag可能由文件名和文件最后被修改的日期组成。无论使用什么方法,你都必须确保这个值是真的是唯一的,不会与其它文件的EntityTag混淆。我希望在自己的应用程序中按照客户、顾客和邮编索引来动态地替被建立的文件命名,并把用作EntityTag的GUID存储在数据库中。

  ZipFileHandler类读取和设置公共的State属性。在完成下载以后,它把State设置为fsDownloadFinished。这个时候你就可以删除临时文件了。这儿一般需要调用Save方法来维持状态。

Public Property State() As DownloadState
 Get
  Return m_nState
 End Get
 Set(ByVal nState As DownloadState)
  m_nState = nState
  ' 可选操作:这个时候你可以自动地删除文件。
  ' 如果状态被设置为Finished ,你就再也不需要这个文件了。
  ' If nState =DownloadState.fsDownloadFinished Then
   ' Clear()
  ' Else
   ' Save()
  ' End If
  Save()
 End Set
End Property


  在文件状态发生改变的任何时候ZipFileHandler都应该调用Save方法,保存文件的状态,这样在以后才能显示给用户。你还可以用它来保存你自己建立的EntityTag。请不要把文件的状态和EntityTag值保存在Application、Session或Cache中--你必须跨越所有的这些这些对象的生命周期来保存信息。

Private Sub Save()
 ' 把该文件下载的状态保存到数据库或XML文件中。
 ' 当然,如果你并没有动态地建立文件,就不需要保存这个状态。
End Sub


  前面提到,示例代码只处理一个已有的文件(download.zip),但是你可以进一步增强这个程序,根据需要建立被请求的文件。

  测试示例代码的时候,你的本地系统或LAN可能太快了,以至于无法中断下载过程,因此我推荐你使用慢速LAN连接(在IIS中减少站点的带宽是一种模拟的方法)或者把服务器放到互联网上。

  在客户端上下载文件仍然很艰难。ISP操作的不对的或配置错误的Web缓冲服务器都可能使大文件下载过程失败,包括下载状况恶化或早期对话终结。如果文件大小超过了255MB,你就应该鼓励顾客使用第三方下载管理软件,尽管某些最新的浏览器内建了基本的下载管理器。

    如果你希望进一步扩展示例代码,查阅一下HTTP规范是有益的。你可以为下载建立MD5校验值,使用Content-MD5头信息添加它们,提供一种验证下载文件完整性的途径。示例代码除了GET和HEAD之外没有涉及到其它的HTTP方法。

转载于:https://www.cnblogs.com/cuihongyu3503319/archive/2012/05/15/2500841.html

相关文章:

ZeroMQ实例-使用ZeroMQ进行windows与linux之间的通信

1、本文包括 1&#xff09;在windows下使用ZMQ 2&#xff09;在windows环境下与Linux环境下进行网络通信 2、在Linux下使用ZMQ 之前写过一篇如何在Linux环境下使用ZMQ的文章 《ZeroMQ实例-使用ZMQ(ZeroMQ)进行局域网内网络通信》&#xff0c;这里就不再赘述。 3、在Windows环境…

线性代数:03 向量空间 -- 基本概念

本讲义是自己上课所用幻灯片&#xff0c;里面没有详细的推导过程&#xff08;笔者板书推导&#xff09;只以大纲的方式来展示课上的内容&#xff0c;以方便大家下来复习。 本章主要介绍向量空间的知识&#xff0c;与前两章一样本章也可以通过研究解线性方程组的解把所有知识点…

如何获得PMP认证证书

​ pmp证书是一项由美国项目管理协会发起的项目管理专业人士认证证书&#xff0c;它属于国际认证类证书&#xff0c;含金量是非常高的&#xff0c;那么如何获得PMP认证证书呢?来看看下面的详细介绍。 如何获得PMP证书? PMP证书的获取是需要参加PMP考试的。我国自1999年引进PM…

UITextField的详细使用

UItextField通常用于外部数据输入&#xff0c;以实现人机交互。下面以一个简单的登陆界面来讲解UItextField的详细使用。&#xff0f;&#xff0f;用来显示“用户名”的labelUILabel* label1 [[UILabelalloc] initWithFrame:CGRectMake(15, 65, 70, 30)];label1.backgroundCol…

06-hibernate注解-一对多单向外键关联

一对多单向外键 1&#xff0c;一方持有多方的集合&#xff0c;一个班级有多个学生&#xff08;一对多&#xff09;。 2&#xff0c;OneToMany(cascade{CascadeType.ALL}, fetchFetchType.LAZY )  //级联关系&#xff0c;抓取策略&#xff1a;懒加载。 JoinColumn(name"c…

线性代数:03 向量空间 -- 矩阵的零空间,列空间,线性方程组解的结构

本讲义是自己上课所用幻灯片&#xff0c;里面没有详细的推导过程&#xff08;笔者板书推导&#xff09;只以大纲的方式来展示课上的内容&#xff0c;以方便大家下来复习。 本章主要介绍向量空间的知识&#xff0c;与前两章一样本章也可以通过研究解线性方程组的解把所有知识点…

学Python培训有什么用

​ Python在近几年的发展非常迅速&#xff0c;在互联网行业Python的薪资也越来越高&#xff0c;不少人开始准备学习Python技术&#xff0c;那么到底学Python培训有什么用呢?来看看下面的详细介绍。 学Python培训有什么用? 学习python可以提高工作效率&#xff0c;使用python&…

SQL压力测试用的语句和相关计数器

将数据库中所有表的所有的内容选一遍: IF object_id(tempdb..#temp) is not null BEGIN DROP TABLE #temp END DECLARE index int DECLARE count int DECLARE schemaname varchar(50) DECLARE tablename varchar(50) set index1 set count(select count(*) from s…

线性代数:04 特征值与特征向量 -- 特征值与特征向量

本讲义是自己上课所用幻灯片&#xff0c;里面没有详细的推导过程&#xff08;笔者板书推导&#xff09;只以大纲的方式来展示课上的内容&#xff0c;以方便大家下来复习。 本章主要介绍特征值与特征向量的知识&#xff0c;前一章我们介绍了线性变换可以把一个向量映射到另一个…

使用Silverlight2的WebClient下载远程图片

在Silverlight 2之前有一个Downloader对象&#xff0c;开发者一般使用Downloader下载图片和文体文件&#xff0c;这个对象在Silverlight 2中作为了一个特性被集成到WebClient类之中&#xff0c;你可以直接使用WebClient的OpenReadAsync方法加载远程图片的URI&#xff0c;然后使…

学习Web前端需要避免哪些错误

很多初学web前端的同学&#xff0c;在学习web前端的时候都会遇到一些错误&#xff0c;虽然有些错误与某一个具体的行为相关&#xff0c;但有些错误却是所有Web开发人员都需要面对的挑战。下面小编就整理一下学习Web前端需要避免哪些错误&#xff0c;希望能够给同学们带来帮助。…

【2012百度之星/资格赛】H:用户请求中的品牌 [后缀数组]

时间限制:1000ms内存限制:65536kB描述馅饼同学是一个在百度工作&#xff0c;做用户请求&#xff08;query&#xff09;分析的同学&#xff0c;他在用户请求中经常会遇到一些很奇葩的词汇。在比方说“johnsonjohnson”、“duckduck”&#xff0c;这些词汇虽然看起来是一些词汇的…

实战:使用Telnet排除网络故障

使用Telnet排除网络故障 如果员工告诉你&#xff0c;他的计算机不能访问网站。你需要断定是他的计算机系统出了问题还是IE浏览器中了恶意插件&#xff0c;或者是网络层面的问题。 如图2-108所示&#xff0c;通过Telnet 服务器的某个端口&#xff0c;就能断定是否访问该服务器的…

线性代数:04 特征值与特征向量 -- 矩阵的相似对角化

本讲义是自己上课所用幻灯片&#xff0c;里面没有详细的推导过程&#xff08;笔者板书推导&#xff09;只以大纲的方式来展示课上的内容&#xff0c;以方便大家下来复习。 本章主要介绍特征值与特征向量的知识&#xff0c;前一章我们介绍了线性变换可以把一个向量映射到另一个…

UI设计培训完之后可以去哪些公司工作

UI设计培训完之后可以去哪些公司工作?这是目前很多学习UI设计或者准备学习UI设计的同学比较关注的一个问题&#xff0c;虽然都知道UI设计的发展前景不错&#xff0c;但是具体学完之后该去哪里工作大家却比较迷茫&#xff0c;来看看下面的详细介绍吧。 UI设计培训完之后可以去哪…

Tomcat详解(下)

配置监听端口 1、编辑配置文件 1234[rootplinuxos ~]# vim /usr/local/tomcat/conf/server.xml <Connector port"80" protocol"HTTP/1.1" ##改成80端口 connectionTimeout"20000" redirectPort"8443" /> 2、重启服务 123456…

线性代数:05 实对称矩阵与二次型

本讲义是自己上课所用幻灯片&#xff0c;里面没有详细的推导过程&#xff08;笔者板书推导&#xff09;只以大纲的方式来展示课上的内容&#xff0c;以方便大家下来复习。 本章是特征值与特征向量知识的延续&#xff0c;根据谱定理可知实对称矩阵可以正交对角化&#xff0c;对…

HDU 2717 Catch That Cow(BFS)

题目链接 好裸&#xff0c;BFS。杭电多组。。2A。。 1 #include <stdio.h>2 #include <string.h>3 int p[100001],o[100001];4 int main()5 {6 int n,k,i,j,start0,end0,num0;7 while(scanf("%d%d",&n,&k)!EOF)8 {9 memset(…

参加web前端培训需要注意什么

web前端在互联网行业的就业形势是非常良好的&#xff0c;是很多人进入到互联网行业的一个首要选择&#xff0c;要想学会web前端技术&#xff0c;一定要参加系统的培训&#xff0c;那么参加web前端培训需要注意什么呢? 参加web前端培训需要注意什么? 一、选择一家靠谱的培训机…

NIO - Scatter/Gather

1.Scatter 从一个Channel读取的信息分散到N个缓冲区中(Buufer). 2.Gather 将N个Buffer里面内容按照顺序发送到一个Channel. Scatter/Gather功能是通道(Channel)提供的 并不是Buffer, Scatter/Gather相关接口 类图 ReadableByteChannel WritableByteChannel 接口提供…

android:themes.xml

按 CtrlC 复制代码按 CtrlC 复制代码本文转自 OldHawk 博客园博客&#xff0c;原文链接&#xff1a;http://www.cnblogs.com/taobataoma/p/3761520.html&#xff0c;如需转载请自行联系原作者

参考答案:01 线性方程组

本篇图文为《线性代数及其应用》这本教材对应习题册的参考答案。 从本章开始&#xff0c;我们一起来学习线性代数的有关知识&#xff0c;线性代数的应用之一就是求解复杂方程问题。所以&#xff0c;我们首先从高中时期利用高斯消元法求解线性方程组谈起&#xff0c;发现可以利…

Java培训都学什么

java行业的快速发展&#xff0c;引起了很多人的关注&#xff0c;越来越多的人选择报java培训机构学习java技术&#xff0c;那么Java培训都学什么呢?零基础的同学是否能学会呢?来看看下面的详细介绍。 Java培训都学什么?主要分为以下几个阶段&#xff1a; 第一阶段&#xff1…

网站架构之统一数据服务平台技术

一、论坛背景 新一代网站架构的使命&#xff0c;敏捷&#xff0c;开发&#xff0c;体验。 敏捷&#xff1a;业务快速增长,每天都要上线大量的小需求,应用系统日益膨胀,耦合恶化&#xff0c;架构越来越复杂,带来更高的开发成本。如何保持业务开发敏捷性? 开放&#xff1a;Faceb…

Oracle 变量绑定与变量窥视合集系列二

二 用示例演示一次硬分析&#xff08;hard parse)和一次软分析&#xff08;soft parse&#xff09;&#xff0c;以及一次更软的分析&#xff08;softer soft parse)&#xff0c;并对给出演示结果 我们先看一个硬解析和软解析关系测试&#xff0c;什么时候硬解析&#xff0c;什么…

参考答案:02 矩阵及其运算

本篇图文为《线性代数及其应用》这本教材对应习题册的参考答案。 本章主要介绍有关矩阵的知识&#xff0c;主要包括矩阵的基本运算&#xff08;加法、数乘、乘法、乘幂、迹、转置&#xff09;&#xff0c;其中乘法最为重要&#xff0c;在计算机图形学中具有大量的应用。如果矩…

web前端培训:本期教程CSS 三大特性

CSS 有三个非常重要的三个特性&#xff1a;层叠性、继承性、优先级&#xff1a; 1. 层叠性 相同选择器给设置相同的样式&#xff0c;此时一个样式就会覆盖(层叠)另一个冲突的样式。层叠性主要解决样式冲突的问题。 层叠性原则&#xff1a; 样式冲突&#xff0c;遵循的原则是就近…

如何在Terminal命令行模式下运行Objective-C

一般Objective-C的代码都在Xcode中调试&#xff0c;今天实验了下如何在命令行模式下运行&#xff0c;还是比较简单的&#xff0c;记录分享一下。 File: xxd.h #include <Foundation/Foundation.h> interface Xxd: NSObject { } - (void) xxdSayHelloTo: (NSString *)name…

人工智能时代,程序员要不要精通算法?

1.如何入门算法&#xff1f;需要学习哪些基础知识&#xff0c;请分享你的经验与建议。 入门算法其实很简单&#xff0c;拿生活中的很多现实问题来解决就可以了。比如商场打折问题&#xff08;是打折划算还是满减划算&#xff09;&#xff0c;百钱买百鸡、猴子分桃、鸡兔同笼等有…

参考答案:03 向量空间

本篇图文为《线性代数及其应用》这本教材对应习题册的参考答案。 本章主要介绍向量空间的知识&#xff0c;与前两章一样本章也可以通过研究解线性方程组的解把所有知识点串联起来&#xff0c;比如研究齐次线性方程组的解可以得到线性相关、线性无关、零空间、解空间的基&#…