多线程实现并发TCP服务器课件.ppt
彭 丹,多线程并发服务器,知识点回顾,1. 多线程2. Socket,1. 多线程,1. 概念 线程是程序中一个单一的顺序控制流程.在单个程序中同时运行多个线程完成不同的工作,称为多线程。2. 共享资源 一个进程的所有线程共享进程的地址空间和全局变量3. 函数 intpthread_create(pthread_t*tidp,constpthread_attr_t*attr,(void*)(*start_rtn)(void*),void*arg); 编译链接参数-pthread,2.Socket,建立TCP连接流程,代码演示1TCP-简单收发,本章知识点,1.并发 2. Linux下tcp并发服务器的几种设计模式3.阻塞4. 如何实现client和server实时收发数据5. 如何实现TCP server同时和多个客户端相连6. 如何实现TCP多个客户端互相通信,1. 并发,概念 当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时,其它线程处于挂起状。这种方式我们称之为并发(Concurrent)。,3. Linux下tcp并发服务器的几种设计模式,多进程模式 accept返回成功时候,就为这一个连接fork一个进程,专门处理这个连接上的数据收发,等这个连接处理结束之后就结束这个进程。 优点: 编程相对简单,不用考虑线程间的数据同步等。 缺点: 资源消耗大。启动一个进程消耗相对比启动一个线程要消耗大很多,同时在处理很多的连接时候需要启动很多的进程多去处理,这时候对系统来说压力就会比较大。另外系统的进程数限制也需要考虑。 应用: 在客户端数据不多的时候使用很方便,比如小于10个客户端。,Linux下tcp并发服务器的几种设计的模式,多线程模式 类似多进程方式,但是针对一个连接启动一个线程。 优点: 相对多进程方式,会节约一些资源,会更加高效一些。 缺点: 相对多进程方式,增加了编程的复杂度,因为需要考虑数据同步和锁保护。另外一个进程中不能启动太多的线程。在Linux系统下线程在系统内部其实就是进程,线程调度按照进程调度的方式去执行的。 应用: 类似于多进程方式,适用于少量的客户端的时候。,Linux下tcp并发服务器的几种设计的模式,select + 多线程 模式 有一个线程专门用于监听端口,accept返回之后就把这个描述符放入 描述符集合 fd中,一个线程用select去轮训描述符集合,在有数据的连接上接收数据,另外一个线程专门发送数据。当然也可以接收和发送用一个线程。描述符可以设置成非阻塞模式,也可以设置成阻塞模式。通常连接设置成非阻塞模式,发送线程独立出来。 优点: 相对前几种模式,这种模式大大提高了并发量。 缺点: 系统一般实现描述符集合是采用一个大数组,每次调用select的时候都会轮询这个描述符数组,当连接数很多的时候就会导致效率下降。连接数在1000以上时候效率会下降到不能接受。应用: 目前windows 和一般的Unix上的tcp并发都采用select方式,应该说应用还是很广泛的。,Linux下tcp并发服务器的几种设计的模式,epoll方式 在Linux2.6版本之后,增加了epoll。具体的使用是:一个线程专门进行端口监听,accept接收到连接的时候,把该连接设置成非阻塞模式,把epoll事件设置成边缘触发方式,加入到epoll管理。接收线程阻塞在epoll的等待事件函数。另外一个线程专门用于数据发送。 优点: 由于epoll的实现方式先进,所以这种方式可以大规模的实现并发。我们现在的应用在一个3年前的dell的pc server可以实现2万个连接的并发。 缺点: 由于涉及了线程和非阻塞,所以会导致编码的复杂度增大一些。这种方式只适用于Linux 2.6内核以后。,1。 如果把epoll事件设置成水平触发效率就下降到类似采用select的水平。 2。Unix系统下有单个进程打开的描述符数目限制,还有系统内打开的描述符数目限制。系统内打开的描述符数目限制由软硬限制两个。硬限制是根据机器的配置而不同。软限制可以更改,但是必须小于系统的硬限制。在suse Linux下,可以在root用户下,通过ulimit -n 数目 去修改这个限制。 应用: Linux下大规模的tcp并发。,注意,当前 并发还有其他的方式,比如进程池,线程池等,每种模式都有它的优点和缺点,在适当的情况用合适的模式是最重要的。 如果需要很大规模的并发,经过测试,采用epoll方式效率比较高。,其他,进程并发:通常用在业务不相关的组件场景中。例如,日志管理、业务管理、系统管理、文件管理通常是放在不同的进程去处理。因为这几种组件处理的业务都是很内聚的,没有共享数据和资源,只有在少量情况下需要互相通信。,场景,多线程并发:比如在业务管理进程中,我们则希望不同类业务数据和资源容易互相访问,但是不同种类的业务逻辑是彼此独立的,即,线程之间会去看共享数据,而线程公平性的调度则交给操作系统。,场景,IO多路复用:是在同一种类型业务中,资源是强相关的,也就是说业务之间会互相看对方的数据或者状态来决定自己的行为,并且我们可能希望控制不同子业务间的执行顺序。而各种子业务间也需要一定的并发性,即,各子业务间不应强行互相等待,保证子业务在等待某种资源时,能够腾出手来干其他子业务。这种方式下,由于是单线程,能够保证一个子业务在访问其他业务的状态和数据时,保持一个稳定状态。,场景,3. 阻塞,1. 阻塞式I/O2. 非阻塞式I/O3. 阻塞函数,概念,阻塞阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,cpu不会给线程分配时间片,即线程暂停运行)。函数只有在得到结果之后才会返回。 快递的例子:比如到你某个时候到A楼一层(假如是内核缓冲区)取快递,但是你不知道快递什么时候过来,你又不能干别的事,只能死等着。但你可以睡觉(进程处于休眠状态),因为你知道快递把货送来时一定会给你打个电话(假定一定能叫醒你)。非阻塞非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。 还是等快递的例子:如果用忙轮询的方法,每隔5分钟到A楼一层(内核缓冲区)去看快递来了没有。如果没来,立即返回。而快递来了,就放在A楼一层,等你去取。,Linux下的五种I/O模型 阻塞式I/O,阻塞式I/O,Linux下的五种I/O模型 非阻塞式I/O,3) I/O复用(select 和poll)(I/O multiplexing)4)信号驱动I/O(signal driven I/O (SIGIO))5)异步I/O(asynchronous I/O (the POSIX aio_functions)),Linux下的五种I/O模型,阻塞函数,accept()函数accept缺省是阻塞函数,阻塞直到有连接请求,将响应连接请求,建立连接,产生一个新的socket描述符来描述该连接,这个连接用来与特定的Client交换信息recv()函数recv缺省是阻塞函数,用于TCP协议中接收信息,直到接收到信息或出错Send()函数recv缺省是阻塞函数,用于TCP协议中发送信息,直到发送完毕或出错,4.,代码演示2TCP同步收发,实现client、server实时收发数据,5.,实现TCP server和多个客户端相连模块图,代码演示3TCP-和多个客户端同时相连-简单连接,5.如何实现TCP多个客户端互相通信,代码演示3TCP-和多个客户端同时相连-广播,