这篇文章对于高手跳过,内容比较初级。有几个概念在服务器端编程时我会经常混淆,估计有些朋友也和我一样。它们是请求(对应响应),连接,线程。这篇短文主要是对这几个概念作了一定的解释,当你理清这些概念以后,就不会习惯性的认为一个请求必须由一个线程处理了,它们之间并没有这种必然的联系。
请求Request
我们经常提到的Request实际上是指客户端发过来的用于对某些资源的访问申请或将一些客户端的数据等发送给服务端的请求,一般一个请求会相应的有一个响应。服务器端收到请求以后会对这个请求作出处理,可能是直接处理掉或者暂时放到请求的队列中等待。大家都知道Web开发中的HttpRequest和HttpResponse,它们就分别代表一个遵循Http协议的请求和一个遵循Http协议的响应,通过请求可以拿到客户端要请求的资源(URl),这个请求的客户端环境,以及请求中携带的提交数据(例如POST方式为提交一些表单数据等),与这个请求对应的响应是Http服务器给客户端的应答,包括处理的结果和一些消息内容等。可以把它们简单理解成客户端提交给服务器的数据和服务器处理这些数据以后给客户端发送的数据,也可以理解为一问一答。
连接Connection
在服务器端编程时连接可能是最重要的概念了,但是很多组件已经把连接的管理封装在了底层框架中(例如协议栈的连接管理模块),所以有时连接对于用户来说是透明的,使用者甚至不知道连接的存在,但是当发现问题时你可能就需要了解连接是如何管理的了。现在我们谈连接的概念已经局限在了Socket连接之上了(实际上是一种规范),因为它实在太广泛了。建立Socket连接时可以绑定TCP或者UDP协议。无论TCP还是UDP都是在传输层控制数据的。一个连接可以理解成一个客户端和服务器的双向数据通道,数据可以在这个通道中传输,实际上这个通道本质上就是网络的节点设备上保存的各种数据结构。要想在节点设备中传输数据就要建立连接,传输完成以后如果不再使用要关闭连接,释放这些数据结构所占用的资源(主要是内存资源),对于客户机来讲,可以对同一服务器并行存在多条连接,在微软的WINDOWS系统中默认可以同时存在2/4连接,这也是长期以来的一个潜规则,当然这个数字也可以通过配置改变或者对于不同的WINDOWS版本会有不同的值。如果对两个节点的连接使用完成以后没有关闭,再去创建连接达到上限以后就会失败,所以一些协议栈的底层框架会有一个很重要的模块就是连接的管理。它一般处理是这样的:打开一个连接以后不断的使用这个连接发送数据,如果发现长时间没有数据传输,那么策略就是关闭这个连接,这个关闭连接的操作可以由客户端发起,也可以由服务器端发起,具体的关闭操作在协议栈上一般会使用客户端的request.close()和response.close()方法实现或者服务器端的request.close()和response.close()方法实现。由此我们就可以理解为什么在应用层的协议中都会有一个类似connection.keepalive=true的东西存在。在我们经常使用的即时聊天工具(例如Fetion)中客户端要想保持这种连接也要不断的发送Keep-Alive信令消息,如果服务器发现在一定的时间内没有收到这个信令消息,则就会主动关闭对这个客户端的连接以释放资源满足其它客户端的连接能力。
线程Thread
这个概念在这里来讲确实有些不合适,因为它是几乎所有编程中都会用到的。在服务器端编程中,线程主要负责处理来自客户端的请求,这里主要想说明的是线程与请求没有直接的对应关系,也就是一个请求不一定由单独一个线程处理(例如ASP.NET中的异步httphandler),但总会有某个线程会处理它。此外线程的创建需要的开销比较大,系统需要分配线程内核对象和一个线程堆栈,为了减少每次创建线程的系统开销,windows线程池产生,代码的最终执行还要落到线程中,所以有关请求的处理也是由线程完成的,很多服务器为了提高吞吐量,会开启多个线程对请求进行处理。例如ASP.NET对于请求的处理就是这样的,一个客户端的请求到达服务器以后,ASP.NET会从.NET的线程池中提出一个空闲的线程处理这个请求,但是如果处理这个请求需要很长时间的话,这个线程就不会被释放回线程池,如果请求大量的并发而来,线程池中没有足够的线程处理这些请求,那么这些请求可能进行排队(缓存在请求队列中)等待空闲线程来处理。对于这些需要长时间处理的IO请求,我们可以使用ASP.NET的异步httphandler来处理,异步httphandler的优点就是可以异步处理请求,这样就可以将工作线程释放回线程池以便处理更多等待着的请求,这样设计毫无疑问可以提高服务器的吞吐量。异步htthandler在结束IO操作以后会执行回调函数来通知请求已经结束,这时ASP.NET可以将这个响应发给客户端了,这个连接也可以在合适的时候关闭了(这里要注意一点就是在回调执行前,在Response返回给客户端前这个连接一直是保持的)。由此可以看出这种异步htthandler只是在服务器端的异步处理,对于客户端是透明的,客户端并不知道服务器端是怎么处理的。如果要想在客户端达到异步的请求提交和响应的获取可以使用AJAX的核心对象XMLHttpRequest实现。同样这个XMLHttpRequest也是受限于默认的2/4并发连接的限制。
总结
这篇短文全都是文字,一点都不美观,大家凑合看吧。其实理解了这几个概念对排查一些问题还是有帮助的,这里主要想说明的就是三者之间没有什么必然的对应关系。其实有时候不知不觉我们就会把他们扯上一些没有必要的关系,这样会限制我们的思维。