《并发服务器》PPT课件.ppt

上传人:小飞机 文档编号:5634089 上传时间:2023-08-04 格式:PPT 页数:58 大小:298.49KB
返回 下载 相关 举报
《并发服务器》PPT课件.ppt_第1页
第1页 / 共58页
《并发服务器》PPT课件.ppt_第2页
第2页 / 共58页
《并发服务器》PPT课件.ppt_第3页
第3页 / 共58页
《并发服务器》PPT课件.ppt_第4页
第4页 / 共58页
《并发服务器》PPT课件.ppt_第5页
第5页 / 共58页
点击查看更多>>
资源描述

《《并发服务器》PPT课件.ppt》由会员分享,可在线阅读,更多相关《《并发服务器》PPT课件.ppt(58页珍藏版)》请在三一办公上搜索。

1、第五章 并发服务器,并发服务器基础多进程服务器多线程服务器I/O多路复用服务器非阻塞socket信号驱动I/O,5.1并发服务器基础(1),理解多客户问题,连接到一个服务器上的多客户示意图服务器以并发方式为多客户提供服务,5.1并发服务器基础(2),服务器分类按连接类型面向连接的服务器 采用TCP协议,可靠。不足之处是:每个连接需要相应的套接字,服务器要管理这些套接字,占用系统资源;连接需要建立和关闭过程,影响传输效率和响应时间,增加服务器负担。无连接的服务器 采用uCP协议,但效率高,占用较少系统资源,服务器不必管理连接套接字。缺点:不可靠,需要程序中实现相应机制。按处理方式重复性服务器:每

2、次只处理一个客户请求,当上一个客户请求处理完成后,才处理下一个请求,简单,效率低。并发服务器:每次可处理多个客户请求,复杂,效率高。,5.1并发服务器基础(3),重复性服务器实现:使用setsockopt()的SO_REUSEADDR选项实现典型代码:int opt,len;len=sizeof(opt)opt=SO_REUSEADDR;setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,实例:源程序名:itrclient.cpp和itrserver.cpp,5.1并发服务器基础(4),功能:服务器等候客户连接,连接显示信息,并循环接收来自客户的信息;收到后显示之,反转

3、后发回客户,直到某客户端输入“bye”关闭连接,就能等待下一客户请求。客户首先与服务器连接,接收键盘输入字符串,发给服务器,接收服务器发回信息并显示,循环,直到bye,关闭连接。运行程序:服务器:%itrserver received client message:1234 客户1:%itrclient connected to server.输入:1234 输出:4321(可以反复输入,均得到反序字符串,直到“bye”为止)思考:客户2、客户3同时运行该程序,结果如何?,5.1并发服务器基础(5),并发服务器与并发技术 进程 进程是程序的一次运行。多个进程可以执行相同的代码(如父子进程),支

4、持并发;单CPU采用分时系统使多个进程同时执行。通过主进程和子进程实现并发,主进程只接收客户请求,子进程只与客户通信。线程 与进程类似,也支持并发。同一进程中的线程共享相同的全程变量和系统分配给该进程的资源,线程间切换更快。进程是最小的资源分配单位,而线程是最小的调度单位。I/O多路复用 系统提供select()函数,在多个描述符中选择被击活的描述符进行操作。如一个服务器同时与多个客户端连接,就有多个TCP套接字描述符,采用时分多路复用技术实现进程或线程的并发处理。,5.1并发服务器基础(6),三种并发服务器算法(1)并发无连接服务器算法 无连接服务,不需要等待每个已连接上的数据,不必采用并发

5、技术也能有效处理多个用户,用多进程/线程需处理大量系统开销,因此无连接服务一般不采用并发技术。(2)并发面向连接服务器算法 通过主进程/线程和子进程/线程实现并发,主进程只接收客户请求,子进程只与客户通信。(3)单进程/线程的并发服务器算法 进程/线程需要较多的系统开销,采用I/O多路复用实现处理多个客户连接,不必产生多个进程/线程。,5.2多进程服务器(1),服务器(父进程),服务器(子进程),listenfdconnfd,connect()函数,客户,连接建立,listenfdconnfd,fork()函数,listenfdconnfd,connect()函数,客户,连接建立,listen

6、fdconnfd,服务器(父进程),服务器(子进程),(a)调用accept()前,(b)调用accept()后,(c)调用fork()后,(d),主服务器进程和子服务器进程实现并发,连接请求,父进程关闭连接套接字子进程关闭侦听套接字,5.2多进程服务器(2),进程概念进程是程序在一个数据集上以并发方式运行的一次过程。进程是程序的动态执行。有生存期。由程序、数据、进程控制块构成。一个进程可包括多个程序,一个程序也可对应多个进程。每个进程有唯一的进程标识符pid。用ps命令看当前系统运行的进程。,5.2多进程服务器(3),系统调用创建进程fork()原型:#include#include pid

7、_t fork(void);功能:创建一个新进程,父子进程共享代码段。返回值:子进程中为0,父进程中为子进程ID,出错为-1。注:用getpid()可以获得当前进程标识符,用getppid()可以获得父进程标识符;通过分支语句控制父子进程执行不同代码(如C/S模式中)。典型代码:pid_t pid;if(pid=fork()0)/*parent process*/else if(pid=0)/*child process*/;exit(0);else cout“fork error!n”;exit(0);,系统中已经有太多的进程或某用户的进程总数超过了系统限制,5.2多进程服务器(4),例1:

8、利用fork()系统调用创建子进程pp1.cpp例2:父子进程享用共同的代码pp2.cpp说明:调用fork()后,父进程/子进程执行顺序不确定程序pp1运行结果 程序pp2运行结果,Just 1 process now.Calling fork()Im the child.Program end.Im the parent.Program end.,pid0=294i=0 j=0 pid=297 ppid=295(4)i=0 j=297 pid=295 ppid=294(2)i=295 j=296 pid=294 ppid=197(1)i=295 j=0 pid=296 ppid=294(3

9、),i=fork(),j=fork(),j=fork(),5.2多进程服务器(5),终止进程exit()、wait()和waitpid1.exit()原型:#include void exit(int status);功能:终止进程,常用于关闭子进程打开的描述符,并返回状态,父进程用wait()、waitpid()获得该状态。返回值:无注:子进程中使用exit()不能完全释放子进程所占用的资源,进程控制块PCB中还保留它的信息,子进程变为“僵尸”进程,ps能看到这样的进程,直到父进程调用wait()后完全释放子进程资源。,5.2多进程服务器(6),父进程可能先于子进程终止,子进程也可能先于父进

10、程终止。2.wait()原型:#include#include pid_t wait(int*stat_loc);功能:在有子进程终止时,系统使用中断信号SIGCHLD通知父进程有子进程终止,此时才能调用wait()。wait()允许父进程取得子进程的状态信息,并挂起,等待子进程终止。返回值:正常,返回子进程进程号,否则-1;同时stat_loc返回子进程返值。典型代码:pid_t pid;int child_status;if(pid=fork()0)/*parent process*/;wait(,5.2多进程服务器(7),原型:#include#include pid_t waitpid

11、(pid_t pid,int*stat_loc,int options);功能:允许父进程取得指定子进程的状态信息,其中:pid是所等待的子进程号,-1时表示第一个子进程;options表示等待的方式,如WNOHANG表示无子进程结束时返回;当pid=-1,options=0时,等价于wait()。返回值:正常,返回子进程号,否则-1;stat_loc返回子进程返值注:若有若干客户同时关闭连接,这些服务进程的父进程同时收到若干SIGCHLD中断信号,由于系统对中断信号无队列设置,导致某些中断信号被丢弃,仍产生“僵尸”进程。waitpid()可以控制无子进程结束时返回。典型代码:clear_ch

12、ild(int signo)int stat,pid;while(pid=waitpid(-1,5.2多进程服务器(8),多进程并发服务器方法用前面所学方法在服务器和客户端建立连接。服务器调用fork()产生子进程。若子进程,关闭监听套接字(保留连接套接字),处理客户请求,最后关闭连接套接字,用exit()退出进程。若父进程,关闭连接套接字(保留监听套接字,套接字描述符的引用计数减1),等待另一客户的连接。,5.2多进程服务器(9),典型代码#include#include#include#include main();listenfd=socket();bind(listenfd,);lis

13、ten(listenfd,);while(1)connfd=accept();if(pid=fork()0)/*parent process*/;close(connfd);continue;else if(pid=0)/*child process*/;close(listenfd);exit(0);else cout“fork errorn”;exit(0);,5.2多进程服务器(10),实例1源程序名:procserver.c和procclient.c功能描述:服务器等候客户连接请求,连接成功后显示客户地址,接收客户名字并显示,循环接收客户字符串并显示,反序处理后发回客户端,服务器可同时

14、处理多客户请求。而客户端先与服务器连接,接收键盘输入的客户名字发给服务器,循环接收用户输入的字符串发给服务器,接收服务器发回的信息并显示,直到D客户关闭连接并退出。运行程序:服务器:$procserver You got a connection from 127.0.0.1.clients name is client1.Received client(client1)message:1234 You got a connection from 127.0.0.1.clients name is client2.Received client(client2)message:abcd,5.2

15、多进程服务器(11),客户1:$procclient Connected to server.Input name:client1 Input string to server:1234 Server Message:4321客户2:$procclient Connected to server.Input name:client2 Input string to server:abcd Server Message:dcba,5.2多进程服务器(12),实例2源程序名:multi.h mulprosrv.cpp mulprocli.cpp功能描述:服务器等候客户连接请求,连接成功后显示客户地

16、址和端口号,循环接收客户的两个整数,相加后发回客户端。服务器可同时处理多客户请求。客户端首先与服务器连接,循环接收用户输入的两个整数发给服务器,接收服务器发回的两数和的信息并显示,询问是否继续(1或0),0返回。运行程序:服务器:$./mulprosrv one client is request service from 127.0.0.1 at PORT 32769(客户1)in process 1231:12+23=35 in process 1231:6+8=14 one client is request service from 202.113.29.19 at PORT 3277

17、0(客户2)in process 2050:2+3=5 client 127.0.0.1 closed child process 1231 cleaned return 0,5.2多进程服务器(13),客户1:$./enter an interger:12 enter another interger:23 12+23=35 would you like to continue(1:continue,0:end):1 enter an interger:6 enter another interger:8 6+8=14 would you like to continue(1:continu

18、e,0:end):0客户2:$./.,5.3多线程服务器(1),线程基础 线程能提高代码响应和性能,线程由系统内核按时间片进行管理,在单处理器系统中,系统内核使用时间分片模拟线程的并发执行,在多处理器系统中,如同多个进程,线程也可以并发执行。同一进程中的线程共享如下内容:全局变量数据虚拟内存打开的文件描述符当前工作目录用户及用户组ID每个线程具有独立的:线程IDerrno变量优先级,5.3多线程服务器(2),POSIX的多线程库1.pthread_create()原型:#include int pthread_create(pthread_t*thread,const pthread_attr

19、_t*attr,void*(*start_func)(void*),void*arg);功能:程序运行时系统产生主线程,该函数产生其它线程,其中:thread:指向线程ID的指针,pthread_t就是unsigned int。attr:指向线程属性的指针,NULL为默认值。start_func:指向线程执行的函数(通用函数指针)。arg:为函数start_func传递参数,若传递多个参数,须封装在一个结构中。返回值:成功返回0,否则返回非零的错误代码。注:fork()创建的子进程与其父进程使用同一个执行点,而pthread_create()中的参数start_func指明新线程要执行的函数,

20、5.3多线程服务器(3),典型代码:#include pthread_t thread;struct ARG int fd;struct sockaddr_in addr;arg;void*start_routine(void*arg);void main()if(pthread_create(/pthread_create()返回非零,表明创建线程失败,5.3多线程服务器(4),2.pthread_exit()原型:#include void pthread_exit(void*value_ptr);功能:终止当前线程,若value_ptr非空则指向线程退出状态。一般用法取NULL。返回值:

21、无,若在线程中调用exit(),将终止该进程所有线程.典型代码:(常用在线程执行的函数中)void*start_routine(void*arg)pthread_exit(NULL);,5.3多线程服务器(5),多线程并发服务器方法用前面所学方法在服务器和客户端建立连接服务器调用pthread_create()产生新线程若主线程,等待另一客户的连接请求若新线程,处理客户请求给新线程传递参数普通方法:使用公共变量传参通过分配arg的空间传递参数注意编译时要和线程库libpthread.a或libpthread.so相连接,如:g+thrserver.cpp o thrserver-lpthrea

22、d,静态链接库,动态链接库,5.3多线程服务器(6),1.普通方法 void*start_routine(void*arg);struct ARG int connfd;int other;void main()struct ARG arg;int listenfd,connfd;pthread_t thread;/*connfd=accept()*/arg.connfd=connfd;arg.other=5;if(pthread_create(,void*start_routine(void*arg)struct ARG info;info.connfd=(struct ARG*)arg)-

23、connfd;info.other=(struct ARG*)arg)-other;close(info.connfd);pthread_exit(NULL);说明:变量arg是所有线程共用的,传递的参数为指针,假设新线程A正处理客户A请求,主线程又接受另一客户B的连接,主线程将修改变量arg内容,故只能处理一个客户,无法同时处理多个客户(不安全)。,5.3多线程服务器(7),5.3多线程服务器(8),2.通过动态分配arg空间传递参数 void*start_routine(void*arg);struct ARG int connfd;int other;void main()int lis

24、tenfd,connfd;ARG*arg;pthread_t thread;/*connfd=accept()*/arg=new ARG;arg-connfd=connfd;arg-other=5;if(pthread_create(,void*start_routine(void*arg)ARG info;info.connfd=(ARG*)arg)-connfd;info.other=(ARG*)arg)-other;close(info.connfd);delete arg;pthread_exit(NULL);说明:创建新线程前,为新线程动态分配存储arg的空间,传递参数给新线程,新线

25、程使用后释放arg。,5.3多线程服务器(9),5.3多线程服务器(10),实例1源程序名:thrserver.cpp和procclient.cpp(方法2传参)功能描述:与5.2中实例1功能相同编译过程:$g+thrserver.cpp o thrserver-lpthread运行程序:服务器:$thrserver You got a connection from 127.0.0.1.clients name is wen.Received client(wen)message:1234 You got a connection from 127.0.0.1.clients name is

26、 zhang.Received client(zhang)message:abcd客户1:$procclient Connected to server.Input name:wen Input string to server:1234 Server Message:4321客户2:$procclient,5.3多线程服务器(11),实例2源程序名:multhrsrv.cpp和mulprocli.cpp(方法1传参)功能描述:与5.2实例2中功能相同,所不同的是服务器采用多线程服务器提供并发服务。运行程序:服务器:$./multhrsrv Process Idis 423 one clien

27、t is request service from 127.0.0.1 at PORT 32769(客户1)thread 1231 will process the request in thread 1231:12+23=35 in thread 1231:6+8=14 one client is request service from 127.0.0.1 at PORT 32770(客户2)thread 2050 will process the request in thread 2050:2+3=5 client 127.0.0.1 closed and thread 1231 TE

28、RMINATE client 127.0.0.1 closed and thread 2050 TERMINATE,5.3多线程服务器(12),线程安全由于同一进程中的所有线程共享相同的存储空间,如果多个线程修改相同的内存区域可能会出现错误,这就是线程安全问题。实例3:源程序名:thrserver1.cpp和procclient.cpp功能描述:修改4.3中实例1,增加一个函数savedata(),希望将每个线程接收的所有信息保存,线程终止时显示,但结果与想象不符。原因是调用了非线程安全的函数savedata(),该函数中包含了一个静态变量(多线程共享变量)结论:在多线程环境中应避免使用静态变

29、量,而采用线程专用数据(TSD)取代静态变量,它是线程私有的,是定义线程私有数据的唯一方法。,5.3多线程服务器(12),运行程序:服务器:$./thrserver1You got a connect from 127.0.0.1.clients name is wen.Received client(wen)message:1234You got a connect from 127.0.0.1.clients name is zhang.Received client(zhang)message:abcReceived client(wen)message:5678Client(wen)c

30、losed connection.users data:1234Received client(zhang)message:defClient(zhang)closed connection.users data:客户1:$procclientConnected to server.Input name:wenInput string to server:1234/依次输入1234、5678和byeServer Message:4321客户2:$procclient 127.0.0.1/依次输入abc、def和bye,5.3多线程服务器(13),与TSD有关的函数 pthread_key_cr

31、eate()原型:#include int pthread_key_create(pthread_key_t*key,void(*destructor)(void*value);功能:在进程内部分配一个标志TSD(线程专用数据)的关键字,创建进程时为NULL,每个线程可以为关键字绑定一个值,该值对绑定的线程是唯一的(创建线程时为NULL),一般创建第一个新线程时使用。其中:key:指向创建的关键字。destructor:为析构函数,若它非空,key也非空,则线程退出时调用析构函数。返回值:正常返回0,否则返回错误码。,5.3多线程服务器(14),pthread_setspecific()原型:

32、#include int pthread_setspecific(pthread_key_t*key,void*value)功能:为TSD关键字绑定一个与本线程相关的值。其中value为相关值。返回值:正常返回0,否则返回错误码。pthread_getspecific()原型:#include void*pthread_getspecific(pthread_key_t*key)功能:获得与调用线程相关的关键字所绑定的值。返回值:正常返回与调用线程相关的关键字所绑定的值,若未绑定返回NULL。,5.3多线程服务器(15),典型代码:(某线程处理函数中)pthread_key_t key;pth

33、read_key_create(,5.3多线程服务器(16),pthread_once()原型:#include void*pthread_once(pthread_once_t*once_control,void(*init_routine)(void);功能:初始化动态包,当设置为PTHREAD_ONCE_INIT时,所指向的函数在同一进程中只被调用一次。其中:once_control=PTHREAD_ONCE_INIT init_routine:初始化时所指向的函数。返回值:正常返回0,否则错误码。,5.3多线程服务器(17),典型代码:static pthread_key_t key;

34、static pthread_once_t once=PTHREAD_ONCE_INIT;static void destructor(void*ptr)delete ptr;static void getkey_once()pthread_key_create(,5.3多线程服务器(18),实例4:源程序名:thrserver2.cpp和procclient.cpp功能描述:修改4.3中实例3,采用线程专用数据(TSD)取代静态变量实现了实例3希望实现的功能。实例5:源程序名:thrserver3.cpp和procclient.cpp功能描述:修改4.3中实例3,另一种常用的方法是通过使用函

35、数的参变量取代静态变量,但需要改变函数的原型以增加相应的参变量,同样实现了实例4的功能(自己看)。,5.4 I/O多路复用服务器(1),多路复用的基本原理当服务器同时处理两个输入流时(如stdio和socket),常常使进程进入阻塞状态。即如果在输入流A中阻塞,则无法处理输入流B中到达的数据,反之亦然。生活中的例子:一个人需分别在两个不同车站接两个人,若先去A站接人,A站人没到,等待,直到接到A站人再去B站接另一人,此时B站人已等候多时,效率低。解决办法:谁先到就给接站的人打电话,然后接人。这种思想就是多路复用的原理。,5.4 I/O多路复用服务器(2),实现机制 服务器采用I/O多路复用技术

36、,由系统内核缓冲I/O数据,当某I/O准备好后,系统通知应用程序该I/O可读或可写,应用程序马上完成相应的I/O操作,这一过程由select()系统调用实现。优势 与多进程和多线程技术相比,I/O多路复用技术系统开销小,不必创建进程/线程,也不必维护这些进程/线程。主要应用客户程序需同时处理交互式输入及与服务器间的网络连接。客户端需同时对多个网络连接作出响应。TCP服务器需同时处理处于监听状态和多个连接状态的套接字。服务器需处理多个网络协议的套接字。服务器需同时处理不同的网络服务和协议。,5.4 I/O多路复用服务器(3),涉及的数据结构、带参数的宏及函数宏名#define FD_SETSIZ

37、E 256(在sys/types.h中)数据结构 fd_set是一个结构(整型数组),存放描述符集合(每个描述符占1位)。该数据类型对用户不透明,需要通过宏进行操作。带参数的宏FD_ZERO(fd_set*fdset)初始化描述符集合,每位置为零FD_SET(int fd,fd_set*fdset)建立描述符fd与fdset的联系FD_CLR(int fd,fd_set*fdset)撤消描述符fd与fdset的联系FD_ISSET(int fd,fd_set*fdset)检查与fdset联系的描述符fd是否可读写,返回非0表示可读写(集合中相应位是否被设置)注:通常为读写分别建立描述符集合,如

38、:fd_set read_socks,write_socks;FD_ZERO(,5.4 I/O多路复用服务器(4),函数select()原型:#include int select(int nfds,fd_set*readfds,fd_set*writefds,fd_set*errorfds,struct timeval*timeout);说明:nfds:select()函数监视描述符值的最大值,一般设为要监视描述符值的最大值加1(描述符从0开始).最大描述符上限定义为FD_SETSIZE,而事实上目前的UNIX版本不作限制(仅受内存量和管理性限制)readfds:select()监视的可读描

39、述符集合.writefds:select()监视的可写描述符集合.errorfds:select()监视的异常描述符集合.timeout:select()函数的超时结束时间.返回值:成功返回总位数,对应已准备好的描述符,否则返回-1,并置errno码。注:readfds,writefds,errorfds中任意一个(或全部)可以为NULL,当全部为NULL时,相当于sleep(),5.4 I/O多路复用服务器(5),编写下列代码:fd_set readset,writeset;FD_ZERO(,fd0,fd3,fd1,readset,writeset,fd2,5.4 I/O多路复用服务器(6)

40、,select()函数实现I/O多路复用的步骤清空描述符集合:FD_ZERO(,5.4 I/O多路复用服务器(7),实例6:源程序名:selectserver.cpp和procclient.cpp功能描述:单线程并发服务器实例,实现功能与例4、例5类似,编程比多进程、多线程并发服务器复杂,若多线程并发服务器I/O多路复用更复杂。运行结果:服务器:$./selectserver Client(wen)closed connection.users data:12345678 Client(zhang)closed connection.users data:abcdef 客户1:$proccli

41、ent/依次输入1234、5678和bye 客户2:$procclient/依次输入abc、def和bye,5.4 I/O多路复用服务器(8),实例7:源程序名:chatserver.cpp和chatclient.cpp功能描述:采用I/O多路复用实现聊天室程序运行程序:服务器:$./chatserver 1234 broadmsg:zhang:hello broadmsg:wang:Hi,zhang 客户1:$./chatclient 202.113.29.19 1234 zhang zhang entered chat room hello(输入的)zhang:hello(广播的)wang

42、:Hi,zhang(广播的)客户2:$./chatclient 202.113.29.19 1234 wang wang entered chat room Hi,zhang(输入的)wang:Hi,zhang(广播的),5.4 I/O多路复用服务器(8),说明:先运行服务器程序客户1进入聊天室,并输入hello,服务器进行广播此时,客户2、客户3依次进入聊天室 若某客户D退出聊天室,则 本客户显示:close chat connection closed 其它客户显示:*is leaving now!若非正常关闭,其它客户显示:*is dropped!,5.5 非阻塞socket(1),进程

43、阻塞一个进程中同时处理多路输入输出流时,常出现进程阻塞TCP socket编程中导致阻塞的系统调用服务器端的accept(),若没有连接请求则进程被阻塞,有连接请求到达时恢复执行.从socket读出数据的read()、recv()系统调用,若读取缓冲区无数据可读(对方发送数据尚未到达),则进程被阻塞.向socket写入数据的write()、sent()系统调用,若写入缓冲区已满(TCP还没来得及送出去),则进程被阻塞.cin在接收到回车输入前,进程被阻塞.UDP socket编程中的recvfrom()和sendto()也导致阻塞,5.5 非阻塞socket(2),非阻塞socket基本原理前

44、面介绍的socket都是阻塞的(默认方式),即当输入输出条件没有准备好,对该socket的操作会导致进程的阻塞。将socket设为非阻塞,在程序中通过轮询来检查socket是否准备好进行输入和输出(不用select)设置非阻塞的系统调用#include int fcntl(int fd,int cmd);int fcntl(int fd,int cmd,long arg);其中:fd是描述符,cmd为要执行的操作,arg为所需参数注意:还可以采用ioctl()改变标志位,5.5 非阻塞socket(3),典型代码#include int flags;flags=fcntl(sockfd,F_G

45、ETFL,0);flags|=O_NONBLOCK;/其中|=表示或等运算 fcntl(sockfd,F_SETFL,flags);注意:直接设置fcntl(sockfd,F_SETFL,O_NONBLOCK);是错误的,因为它将清除掉其他所有的标志。,5.5 非阻塞socket(4),阻塞与非阻塞工作方式比较,5.5 非阻塞socket(5),实例8:非阻塞UDP socket源程序名:改写udptalk.cpp为udptalk4.cpp功能描述:采用非阻塞UDP socket实现聊天室程序运行程序:客户1:./udptalk4 127.0.0.1 1111 202.113.29.19 22

46、22客户2:./udptalk4 202.113.29.19 2222 127.0.0.1 1111客户3:./udptalk4 202.113.29.19 2222 127.0.0.1 3333运行结果:可以进行多人聊天,且不需互相等待.,5.5 非阻塞socket(6),实例9:非阻塞TCP socket源程序名:改写echocli.cpp为echocli2.cpp作为客户端程序,服务器端可采用多进程并发服务器实现。功能描述:采用非阻塞TCP socket实现回显程序系统调用:int shutdown(int sockfd,int how);其中:how=0,关闭读通道;how=1,关闭写

47、通道;how=2,关闭读写通道。接收通道(读通道)不能由客户端关闭,只有服务器接收到客户端FIN信号后,可关闭相应的接收通道;客户端可以关闭发送通道(写通道)。运行程序:服务器:./procserver 客户1:./客户2:./,5.5 非阻塞socket(7),curline,sndmsg,curline,curline,sndmsg,sndmsg,pos=5,pos=9,pos=7,Socket发送缓冲未满,Stdin继续有数据到达,发送缓冲未满,发送一条消息后,继续从stdin输入,5.6 信号驱动输入输出(1),信号驱动I/O基本原理信号驱动输入输出是实现在一个进程中同时处理多个输入输

48、出流的另一种方法。基于中断技术。设置标志位O_ASYNC,若有I/O事件发生,系统将SIGIO信号发送给进程。信号驱动I/O的特点中断发生时进入中断处理程序处理I/O,没有中断时还可进行其它操作,不会进入阻塞状态。信号驱动的中断方式比非阻塞的轮询方式响应速度快。,5.6 信号驱动输入输出(2),信号驱动I/O的实现步骤将需要信号驱动控制的多个句柄的属主设为同一进程fcntl(fd,F_SETOWN,PID);将这些句柄的标志位O_ASYNC打开,可发送SIGIO信号ioctl(fd,FIOASYNC,有I/O事件发生时,系统向进程发送SIGIO信号,进行相应处理。不进行具体实例分析了,可以看有关书籍,总结,多进程、多线程、I/O多路复用、非阻塞socket、信号驱动I/O都可用于服务器端,实现同时对多个客户提供服务I/O多路复用、非阻塞socket、信号驱动I/O既可用于服务器端,又可用于客户端,将不同的套接口或键盘、显示器等被视为不同的输入/输出流来处理,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号