注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

云水居

云在青山水在天,人在江湖不得闲

 
 
 

日志

 
 

Linux内核与Nginx  

2010-08-19 11:40:11|  分类: 默认分类 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

查看全文


C/S模型有很多种结构,分为几个层次,但其基本原理,就是多线程/多进程与多路IO的使用。
1. 简单层次:
服务器调用socket的accept进入阻塞,收到客户端请求后进行处理,详细过程参见1-0交互式测试C/S,简单层次的服务器即是单纯的使用以下三种技术之一:
1.1. 多线程
每收到一个客户端请求后,都创建一个新线程,然后在新线程里对客户端进行处理,主线程继续等待客户端连接。
这个是最常用的模型,基本学习C/S编程都会学到,参见1.1多线程C/S服务端代码。
1.2. 多进程
每收到一个客户端请求后,都创建一个新进程,然后在新进程里对客户端进行处理,主进程继续等待客户端连接。
这个方式并不常用,因为复制进程的开销太大,而且没有必要,参见1.2多进程C/S服务端代码。但是多进程的思想可以在其它情况下使用,如Apache服务器就用到了多进程。参见2
1.3. select/poll
多线程和多进程都提供了很简单的编程模型,但是在客户端请求非常频繁的时候,由线程或进程切换带来的开销就会慢慢成为性能瓶颈。

2. 中级层次
实际应用中,一般都是对以上三种基本方式进行组合与优化,例如Apache服务器,一般开5个进程,使用select进行多路IO处理。

3. 高级层次epoll
多路IO是一个很好的思想,问题是基于select与poll的多路方法效率并不高,通过翻阅Linux内核源代码可以知道,每次调用select里,都要先把所有的文件描述符从用户空间拷贝到内核空间,然后在内核空间里遍历每个文件描述符,当文件描述符较多时,这两个过程都会成为性能瓶颈。
在Linux2.6内核中,出现了新的处理多路IO的API,epoll,epoll 的机制与select不同,首先调用epoll_ctl将所有文件描述符拷入内核空间,以后每次调用epoll_wait时就不用重复拷贝了,然后在判断就绪的文件描述符时,采用了一个就绪队列,文件描述符就绪时加入就绪队列,每次epoll_wait时只要检查就绪队列就可以了,不用遍历列表。
这两个特性使epoll的性能比select有了很大的提高,最新的Nginx即采用epoll机制,市场占有率上升很快,虽然无法替代Apache的地位,但是在很多时候可以取得比Apache好的性能。用户也越来越多。
最新版的Python才支持epoll,后面的代码3. epoll的CS服务端代码


代码1-0 交互式测试C/S
Server端:
hankjin@jnfdaj:~$ python
>>> from socket import *
>>> server=socket(AF_INET,SOCK_STREAM,0)
>>> server.bind(("0.0.0.0",9999))
>>> server.listen(0)
>>> client,caddr=server.accept()
>>> client.recv(256)
'hello, this is hank\r\n'
>>> client.send('hi, this is jack')
16
>>> client.close()
Client端
hankjin@jnfdaj:~/src/nginx$ telnet localhost 9999
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
hello, this is hank
hi, this is jackConnection closed by foreign host.
代码1.0 1对1C/S服务端代码
#!/usr/bin/python
from socket import *
server=socket(AF_INET,SOCK_STREAM,0)
server.bind(("0.0.0.0",9999))
server.listen(0)
client,caddr=server.accept()
client.recv(256)
client.send('hi, this is jack')
client.close()
代码1.1 多线程C/S服务端代码
#!/usr/bin/python
from socket import *
import thread
def servClient(sock,addr):
    print addr
    sock.recv(256)
    sock.send('hi, this is from thread')
    sock.close()
server=socket(AF_INET,SOCK_STREAM,0)
server.bind(("0.0.0.0",9999))
server.listen(0)
while True:
    client,caddr=server.accept()
    thread.start_new_thread(servClient,(client,caddr,))
代码1.2 多进程C/S服务端代码
#!/usr/bin/python
from socket import *
import thread,os,sys
def servClient(sock,addr):
    print addr
    sock.recv(256)
    sock.send('hi, this is from thread')
    sock.close()
    print 'over'
server=socket(AF_INET,SOCK_STREAM,0)
server.bind(("0.0.0.0",9999))
server.listen(0)
while True:
    client,caddr=server.accept()
   

查看全文

  评论这张
 
阅读(1047)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017