作者:CppExplore 网址:http://www.cppblog.com/CppExplore/
本章主要列举服务器程序的各种网络模型,示例程序以及性能对比后面再写。
一、分类依据。服务器的网络模型分类主要依据以下几点
(1)是否阻塞方式处理请求,是否多路复用,使用哪种多路复用函数
(2)是否多线程,多线程间如何组织
(3)是否多进程,多进程的切入点一般都是accept函数前
二、分类。首先根据是否多路复用分为三大类:
(1)阻塞式模型
(2)多路复用模型
(3)实时信号模型
三、详细分类。
1、阻塞式模型根据是否多线程分四类:
(1)单线程处理。实现可以参见http://www.cppblog.com/CppExplore/archive/2008/03/14/44509.html后面的示例代码。
(2)一个请求一个线程。
主线程阻塞在accept处,新连接到来,实时生成线程处理新连接。受限于进程的线程数,以及实时创建线程的开销,过多线程后上下文切换的开销,该模型也就是有学习上价值。
(3)预派生一定数量线程,并且所有线程阻塞在accept处。
该模型与下面的(4)类似与线程的领导者/追随者模型。
传统的看法认为多进程(linux上线程仍然是进程方式)同时阻塞在accept处,当新连接到来时会有“惊群”现象发生,即所有都被激活,之后有一个获取连接描述符返回,其它再次转为睡眠。linux从2.2.9版本开始就不再存在这个问题,只会有一个被激活,其它平台依旧可能有这个问题,甚至是不支持所有进程直接在accept阻塞。
(4)预派生一定数量线程,并且所有线程阻塞在accept前的线程锁处。
一次只有一个线程能阻塞在accept处。避免不支持所有线程直接阻塞在accept,并且避免惊群问题。特别是当前linux2.6的线程库下,模型(3)没有存在的价值了。另有文件锁方式,不具有通用性,并且效率也不高,不再单独列举。
(5)主线程处理accept,预派生多个线程(线程池)处理连接。
类似与线程的半同步/半异步模型。
主线程的accept返回后,将clientfd放入预派生线程的线程消息队列,线程池读取线程消息队列处理clientfd。主线程只处理accept,可以快速返回继续调用accept,可以避免连接爆发情况的拒绝连接问题,另加大线程消息队列的长度,可以有效减少线程消息队列处的系统调用次数。
(6)预派生多线程阻塞在accept处,每个线程又有预派生线程专门处理连接。
(3)和(4)/(5)的复合体。
经测试,(5)中的accept线程处理能力非常强,远远大于业务线程,并发10000的连接数也毫无影响,因此该模型没有实际意义。
总结:就前五模型而言,性能最好的是模型(5)。模型(3)/(4)可以一定程度上改善模型(1)的处理性能,处理爆发繁忙的连接,仍然不理想。。阻塞式模型因为读的阻塞性,容易受到攻击,一个死连接(建立连接但是不发送数据的连接)就可以导致业务线程死掉。因此内部服务器的交互可以采用这类模型,对外的服务不适合。优先(5),然后是(4),然后是(1),其它不考虑。
2、多路复用模型根据多路复用点、是否多线程分类:
以下各个模型依据选用select/poll/epoll又都细分为3类。下面个别术语采用select中的,仅为说明。
(1)accept函数在多路复用函数之前,主线程在accept处阻塞,多个从线程在多路复用函数处阻塞。主线程和从线程通过管道通讯,主线程通过管道依次将连接的clientfd写入对应从线程管道,从线程把管道的读端pipefd作为fd_set的第一个描述符,如pipefd可读,则读数据,根据预定义格式分解出clientfd放入fd_set,如果clientfd可读,则read之后处理业务。
此方法可以避免select的fd_set上限限制,具体机器上select可以支持多少个描述符,可以通过打印sizeof(fd_set)查看,我机器上是512字节,则支持512×8=4096个。为了支持多余4096的连接数,此模型下就可以创建多个从线程分别多路复用,主线程accept后平均放入(顺序循环)各个线程的管道中。创建5个从线程以其对应管道,就可以支持2w的连接,足够了。另一方面相对与单线程的select,单一连接可读的时候,还可以减少循环扫描fd_set的次数。单线程下要扫描所有fd_set(如果再最后),该模型下,只需要扫描所在线程的fd_set就可。
(2)accept函数在多路复用函数之前,与(1)的差别在于,主线程不直接与从线程通过管道通讯,而是将获取的fd放入另一缓存线程的线程消息队列,缓存线程读消息队列,然后通过管道与从线程通讯。
目的在主线程中减少系统调用,加快accept的处理,避免连接爆发情况下的拒绝连接。
(3)多路复用函数在accept之前。多路复用函数返回,如果可读的是serverfd,则accept,其它则read,后处理业务,这是多路复用通用的模型,也是经典的reactor模型。
(4)连接在单独线程中处理。
以上(1)(2)(3)都可以在检测到cliendfd可读的时候,把描述符写入另一线程(也可以是线程池)的线程消息队列,另一线程(或线程池)负责read,后处理业务。
(5)业务线程独立,下面的网络层读取结束后通知业务线程。
以上(1)(2)(3)(4)中都可以将业务线程(可以是线程池)独立,事先告之(1)、(2)、(3)、(4)中read所在线程(上面1、2、4都可以是线程池),需要读取的字符串结束标志或者需要读取的字符串个数,读取结束,则将clientfd/buffer指针放入业务线程的线程消息队列,业务线程读取消息队列处理业务。这也就是经典的proactor模拟。
总结:模型(1)是拓展select处理能力不错选择;模型(2)是模型(1)在爆发连接下的调整版本;模型(3)是经典的reactor,epoll在该模型下性能就已经很好,而select/poll仍然存在爆发连接的拒绝连接情况;模型(4)(5)则是方便业务处理,对模型(3)进行多线程调整的版本。带有复杂业务处理的情况下推荐模型(5)。根据测试显示,使用epoll的时候,模型(1)(2)相对(3)没有明显的性能优势,(1)由于主线程两次的系统调用,反而性能下降。
3、实时信号模型:
使用fcntl的F_SETSIG操作,把描述符可读的信号由不可靠的SIGIO(SYSTEM V)或者SIGPOLL(BSD)换成可靠信号。即可成为替代多路复用的方式。优于select/poll,特别是在大量死连接存在的情况下,但不及epoll。
四、多进程的参与的方式
(1)fork模型。fork后所有进程直接在accept阻塞。以上主线程在accept阻塞的都可以在accept前fork为多进程。同样面临惊群问题。
(2)fork模型。fork后所有进程阻塞在accept前的线程锁处。同线程中一样避免不支持所有进程直接阻塞在accept或者惊群问题,所有进程阻塞在共享内存上实现的线程互斥锁。
(3)业务和网络层分离为不同进程模型。这个模型可能是受unix简单哲学的影响,一个进程完成一件事情,复杂的事情通过多个进程结合管道完成。我见过进程方式的商业协议栈实现。自己暂时还没有写该模型的示例程序测试对比性能。
(4)均衡负载模型。起多个进程绑定到不同的服务端口,前端部署lvs等均衡负载系统,暴露一个网络地址,后端映射到不同的进程,实现可扩展的多进程方案。
总结:个人认为(1)(2)没什么意义。(3)暂不评价。(4)则是均衡负载方案,和以上所有方案不冲突。
以上模型的代码示例以及性能对比后面给出。
原文地址 http://www.cnblogs.com/shelvenn/articles/969227.html
第二部分
第一章
客户机设置
UDP 客户机的前几行与 TCP 客户机的对应行完全相同。我们主要是使用了几个 include 语句来包含 socket 函数,或其他基本的 I/O 函数。
#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
多路复用的方式是真正实用的服务器程序,非多路复用的网络程序只能作为学习或着陪测的角色。本文说下个人接触过的多路复用函数:select/poll /epoll/port。kqueue的*nix系统没接触过,估计熟悉了上面四种,kqueue也只是需要熟悉一下而已。
一、select模型
select原型:
int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
http://blog.chinaunix.net/u2/67780/showart_2057153.html
WINDOWS完成端口编程
1、基本概念
2、WINDOWS完成端口的特点
3、完成端口(Completion Ports )相关数据结构和创建
4、完成端口线程的工作原理
5、Windows完成端口的实例代码
Linux的EPoll模型
1、为什么select落后
2、内核中提高I/O性能的新方法epoll
3、epoll的优点
4、epoll的工作模式
5、epoll的使用方法
6、Linux下EPOll编程实例
总结
原文地址 http://blog.chinaunix.net/u/26257/showart.php?id=2026219
介绍
Hey! Socket 编程让你沮丧吗?从 man pages 中很难得到有用的信息吗?你想 跟上时代去做一做 Internet 程序,但是为你在调用 connect() 前的 bind() 的结构而愁眉不展?…
好了,我现在已经来了,我将和所有人共享我的知识了。如果你了解 C 语言并想穿过 网络编程的沼泽,那么你来对地方了。
读者
这个文档是写成一个指南,而不是参考书。如果你刚开始 socket 编程并想找一本 入门书,那么你是我的读者。这可不是一本完全的 socket 编程书。
平台和编译器
这篇文章中的大多数代码都在一台 Linux PC 上用 GNU 的 gcc 成功编译过。 而且他们在一台 HPUX 上用 gcc 也成功编译过。但是注意,并不是每个代码 片段都独立测试过。
——————————————————————————–
目录:
什么是套接口?
Internet 套接口的两种类型
网络理论
struct–要么了解他们,要么等异形入侵地球
Convert the Natives!
IP 地址和如何处理他们
socket()–得到文件描述符!
bind()–我们在哪个端口?
connect()–Hello!
listen()–有人给我打电话吗?
accept()–"Thank you for calling port 3490."
send() 和 recv()–Talk to me, baby!
sendto() 和 recvfrom()–Talk to me, DGRAM-style
close() 和 shutdown()–滚开!
getpeername()–你是谁?
gethostname()–我是谁?
DNS–你说“白宫”,我说 "198.137.240.100"
客户-服务器背景知识
简单的服务器
简单的客户端
数据报 Socket
阻塞
select()–多路同步 I/O,酷!
大数据量的问题是很多面试笔试中经常出现的问题,比如baidu google 腾讯 这样的一些涉及到海量数据的公司经常会问到。
下面的方法是我对海量数据的处理方法进行了一个一般性的总结,当然这些方法可能并不能完全覆盖所有的问题,但是这样的一些方法也基本可以处理绝大多数遇到的问题。下面的一些问题基本直接来源于公司的面试笔试题目,方法不一定最优,如果你有更好的处理方法,欢迎与我讨论。
今天在水木上十大看到一个帖子<<小时候最勇敢的事>>,里面回帖的内容倒也十分有趣,让我也不免想起以前儿时的囧事。哎,竟然发现当年我也是一个比较调皮的家伙,不过那应该是在上学之前的时光了,虽然在上学的日子里也发生了一些离奇的事情,现在看来,我经历的离奇的事情还是比较多的,即使后来到了大学,也是如此。
转载请注明作者:phylips@bmy 出处:http://duanple.blog.163.com/blog/static/70971767200910158392605/
概率部分
1.某城市发生了一起汽车撞人逃跑事件,该城市只有两种颜色的车,蓝15%绿85%,事发时有一个人在现场看见了,他指证是蓝车,但是根据专家在现场分析,当时那种条件能看正确的可能性是80%那么,肇事的车是蓝车的概率到底是多少?
摘自<<白话庄子>>
惠子对庄子说:“魏王给我一粒大葫芦的种子,我把它种在地里,结出来的葫芦有五石之大的容量。用它盛水,它不够坚固,把它切开做成瓢,却没有那么大的水缸,这个葫芦不能算不大了,可是却没有任何用处,于是我把它砸碎了”。
http://www.cppblog.com/sandy/archive/2005/12/14/1745.html
今天研究了一下vc6函数调用,看看vc6调用函数时候都做了什么。有些意思。
我写下了如下代码:
int fun(int a,int b)
{
int i = 3;
return a+b+i;
}
http://javagp.group.javaeye.com/group/topic/12269
一、因情制宜,建立“适当”的索引
建立“适当”的索引是实现查询优化的首要前提。
索引(index)是除表之外另一重要的、用户定义的存储在物理介质上的数据结构。当根据索引码的值搜索数据时,索引提供了对数据的快速访问。事实上,没有索引,数据库也能根据SELECT语句成功地检索到结果,但随着表变得越来越大,使用“适当”的索引的效果就越来越明显。注意,在这句话中,我们用了“适当”这个词,这是因为,如果使用索引时不认真考虑其实现过程,索引既可以提高也会破坏数据库的工作性能。
http://www.kuqin.com/networkprog/20080512/8361.html
什么是Socket
Socket接口是TCP/IP网络的API,Socket接口定义了许多函数或例程,程序员可以用它们来开发TCP/IP网络上的应用程序。要学Internet上的TCP/IP网络编程,必须理解Socket接口。
Socket接口设计者最先是将接口放在Unix操作系统里面的。如果了解Unix系统的输入和输出的话,就很容易了解Socket了。网络的 Socket数据传输是一种特殊的I/O,Socket也是一种文件描述符。Socket也具有一个类似于打开文件的函数调用Socket(),该函数返 回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。常用的Socket类型有两种:流式Socket (SOCK_STREAM)和数据报式Socket(SOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。
线程的调度
1.调整线程优先级:Java线程有优先级,优先级高的线程会获得较多的运行机会。
Java线程的优先级用整数表示,取值范围是1~10,Thread类有以下三个静态常量:
static int MAX_PRIORITY
线程可以具有的最高优先级,取值为10。
static int MIN_PRIORITY
线程可以具有的最低优先级,取值为1。
static int NORM_PRIORITY
分配给线程的默认优先级,取值为5。
Thread类的setPriority()和getPriority()方法分别用来设置和获取线程的优先级。
每个线程都有默认的优先级。主线程的默认优先级为Thread.NORM_PRIORITY。
线程的优先级有继承关系,比如A线程中创建了B线程,那么B将和A具有相同的优先级。
JVM提供了10个线程优先级,但与常见的操作系统都不能很好的映射。如果希望程序能移植到各个操作系统中,应该仅仅使用Thread类有以下三个静态常量作为优先级,这样能保证同样的优先级采用了同
转载请注明译者:phylips@bmy 出处:http://duanple.blog.163.com/blog/static/7097176720099402916150/
实现
Thompson在1968年的论文里对多状态模拟策略进行了介绍。在他的文章里,NFA的状态是使用机器码序列来表示的,可能状态列表仅仅是一系列的函数调用指令。实际上,Thompson将正则表达式编译成了机器码。四十年后,计算机已经变得很快了,所以机器码的这种方法变得不太必要了。下面的章节里介绍一种使用标准c的实现。完整的源代码(少于400行)和测试脚本在这里(http://swtch.com/~rsc/regexp/)。
————————–虽然在java perl php python ruby里它很慢
Author:Russ Cox Email:rsc January 2007
[说明:本文由phylips@bmy翻译自英文文章Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby, …),原文地址:http://swtch.com/~rsc/regexp/regexp1.html]
转载请注明作者:phylips@bmy 出处: http://duanple.blog.163.com/blog/static/7097176720098303134160/
概述
在正则表达式领域,有一本广为推崇的书籍<<精通正则表达式>>,但是作者在书中的很多地方假设那些匹配引擎采用的是回溯的算法。但是实际情况是有些引擎采用的NFA,DFA模拟算法,比如grep,awk,sed,对于它们来说算法复杂度是多项式级的。同时采用回溯的一些引擎也在逐步改进,比如通过采用备忘录方法,记住已经回溯到达的状态,防止重复,也可以避免指数级的复杂度。
Brian W. Kernighan and Rob Pike
[说明:本文由phylips@bmy翻译自Regular Expressions Languages, algorithms, and software 1999-01 Author: Brian W. Kernighan and Rob Pike。Brain 和 Rob是朗讯科技贝尔实验室的研究人员,可以通过他们各自的邮件bwk@bell-labs.com and rob@bell-labs.com联系他们。]
原文链接:http://www.ddj.com/architect/184410904?pgno=1,转载请保留全部信息。
1. 给你A,B两个文件,各存放50亿条URL,每条URL占用64字节,内存限制是4G,让你找出A,B文件共同的URL。
2. 有10个文件,每个文件1G, 每个文件的每一行都存放的是用户的query,每个文件的query都可能重复。要你按照query的频度排序
3. 有一个1G大小的一个文件,里面每一行是一个词,词的大小不超过16个字节,内存限制大小是1M。返回频数最高的100个词
http://blog.csdn.net/nileel/archive/2008/06/03/2508918.aspx
今天下午去微软面试,被问到了海量数据查询优化的问题,由于平时开发的应用数据量比较小,不太关注性能优化的问题,所以不知如何作答,很是郁闷。从网上搜索出海量数据查询优化的两篇文章,转载下来,权当学习性能优化的开始。
http://www.cnblogs.com/neoragex2002/archive/2007/11/01/VC8_Object_Layout_Secret.html
哈哈,从M$ Visual C++ Team的Andy Rich那里又偷学到一招:VC8的隐含编译项/d1reportSingleClassLayout和/d1reportAllClassLayout 。看个复杂的例子吧(如下),现在假设我们想知道Derived类的对象布局,怎么办? 在Project Properties->C++->Command Line->Additional Options里面加上/d1reportSingleClassLayoutDerived吧!