ImageVerifierCode 换一换
格式:DOCX , 页数:16 ,大小:31.51KB ,
资源ID:12127736      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/12127736.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(实验五多线程并发服务器编程.docx)为本站会员(b****5)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

实验五多线程并发服务器编程.docx

1、实验五多线程并发服务器编程实验五、多线程并发服务器编程一、实验目的1、 学习Linux操作系统的多线程的基本概念以及进程与线程的区别;2、 掌握编写多线程程序的一般方法;3、 熟悉多线程并发服务器的设计思路,以及多线程程序的编译方法。二、实验容线程(thread )技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在 80年代中期,Solaris是这方面的佼佼者。现在多线程技术已经被许多操作系统所支持,包 括 Windows/NT 以及 Unix/Linux。为什么有了进程的概念后, 还要再引入线程呢?使用多线程到底有哪些好处?什么的系统应该选用多线程?使用多线程的理由之一是和进程相

2、比, 它是一种非常”节俭”的多任务操作方式。在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数 据表来维护它的代码段、堆栈段和数据段,这是一种 ”昂贵的多任务工作方式。而运行于一个进程中的多个线程, 它们彼此之间使用相同的地址空间, 共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间, 而且线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计一个进程的开销大约是一个线程开销的 30倍左右。使用多线程的理由之二是线程间方便的通信机制。 对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且

3、很不方便。 线程则不然,由于同一进程下的线程之间共享数据空间, 所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不 能同时被两个线程所修改,有的子程序中声明为 static的数据更有可能给多线程程序带来灾 难性的打击,这些正是编写多线程程序时最需要注意的地方。1、编写一个最简单的多线程程序请仔细运行、分析下列程序,指出多进程和多线程如何区分?何谓父线程和子线程?当 父线程终止会导致子线程发生何种情况?/*文件名:pthread_example.c演示了 pthread_create函数创建子线程的使用*/#i nclude #i nc

4、lude / 创建多线程void childThread();int mai n()int i = 0; pthread_t id;pthread_create(&id,NULL,childThread,NULL); printf(”点击回车键结束运行n);getchar();void childThread()int i;for(i=0;)prin tf(child thread sleep %dn,i+1); sleep(1);编译多线程程序需要用到特殊的库文件 libthread.so ,而我们在以前的实验中的编译程序的方式使用的是标准库函数, 不需要特别指定。因此编译多线程的程序时必须

5、使用 -选项,该选项后面直接跟库文件名称,但要去掉 lib和后缀名,即 -thread。注意-l是lib的首字母。例如如果需要用到数学函数库 libm.so则编译程序时需要使用选项 -m。按以前实验方式编译该程序发现错误, 图1中红色部分为错误信息,该信息表明程序未找到函数pthread_create的实现。图2为编译正确的结果显示。V I Idcj llkh L/hoin c/mql文件编辑虫) 终端转到fg)i口c L 1 u ea I Liu t 門 I ” g cc - v c xaiip I e p t hi ead e le . cpthread In func t ion ivh

6、 in ;pihrf ad.txanple . c : 12; varn iupi pass in arg 3 nf p(tiread_reate fjf tnp/ccKg hiSr .d( . lex 10x25: Ln func t icii mi in :unde f med reie rence lc p tki ead_c rea ie I k et2 :Id returned I exit status Jrootloea I ho st nq 叮 H |图1、未使用-lpthread选项错误文i牛 編幄necv) 终需cd 转到垃) 帮RKtpiqo t Moca 1 ha i

7、1 n llff gcc 一 o earrp le pttiread_exanplec - I p threadpitiread_eicaTTple r c: In func I ion na ii;p th r e a d _exa rrp I e . c : 12 ruling】 pa n s i ng arg 3 of p thrad_crea le J f remIp points! typeroot OLo-cs Iho t rq I I*图2、正确使用-Ipthread选项编译结果2、多线程并发服务器编程类似于多进程服务器编程,本实验的多线程并发服务器也分为两部分程序:服务器程序

8、和客户端程序。其中客户端部分和实验一中的客户端部分是一致的, 在本实验中我们作了简化;请注意本实验中的客户端只是为了测试并发服务器的功能, 它们本身并不属于多线程并发服务器的容。服务器部分实现了多线程的功能,父线程不断地( for循环)等待客户端的连接,一旦有客户端连接服务器,服务器则创建( pthread_create )一个子线程用于该客户端的接收数据处理。在验证结果阶段可以同时启动多个客户端, 注意服务器只需要启动一次。显而易见的是随着客户端数量的增加,服务器子线程的数量也将线性增加,这必将加重 服务器硬件资源(存)的消耗,最终可导致服务器硬件资源耗尽而崩溃。但与实验六中多进 程并发服务

9、器相比,对同等数量的多线程和多进程程序而言, 多线程程序对存的需求明显低于多进程程序。本次实验中的客户端程序作了更多的简化, 采用单文件方式。客户端部分未用到多线程,其编译方法与以前的实验一致。服务器部分仍然采用多文件方式, 因此在编译运行时要用到多个C文件,注意编译时要加上 -thread选项。分析、运行下列代码,建议由两位同学分别运行服务器和客户端,然后再转换角色分析 程序。1 )客户端程序源码/*文件名:TCPSimpleClie nt.c描述:一个简单的 TCP客户端例子,发送 hello world给服务器,并接收服务器返回*/#i nclude #i nclude #in clud

10、e #in clude #in clude #in clude #in clude int main (i nt argc, char *argv)if (argc != 3)printf(使用方式必须为:$命令服务器地址服务器端口号n); return 1;char *ip = argv1;char *port = argv2;int cs = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP);if (cs 0)printf(创建套接字失败n”);return -1;struct sockaddr_ in serv;memset (&serv, 0, s

11、izeof (serv);serv.s in _port = hton s(atoi(port);in et_pt on (AFN ET,ip, &serv.s in _addr.s_addr);serv.sin_family = AF_INET;printf(开始与服务器建立连接!n);if(conn ect (cs, (struct sockaddr *)& serv, sizeof(serv)0)printf(连接失败!n”);return -1;printf(连接成功!n);char buf100 = hello world;sen d(cs, buf, strle n( buf),

12、0);memset(buf,0,sizeof(buf);recv(cs,buf,sizeof(buf)-1,0);printf(服务器返回信息:%sn,buf);close(cs);return 0;2)服务器源码服务器源码涉及四个 C文件和一个头文件,各文件容如下:/*文件名:Practical.h*/#ifndef PRACTICAL_H_#defi ne PRACTICAL_H_#in clude #i nclude #in clude void DieWithUserMessage(c onst char *msg, const char *detail);void DieWithSy

13、stemMessage(c onst char *msg);void Prin tSocketAddress(c onst struct sockaddr *address, FILE *stream);bool SockAddrsEqual(c onst struct sockaddr *addr1, const struct sockaddr *addr2); int SetupTCPServerSocket(c onst char *service);int AcceptTCPC onnection (i nt servSock);void HandleTCPClient(int cln

14、tSocket);int SetupTCPClie ntSocket(c onst char *server, const char *service);enum sizeC on sta nts MAXSTRINGLENGTH = 128,BUFSIZE = 512,;#en dif / PRACTICAL_H_/*文件名:msg.c*/#i nclude #i nclude void DieWithUserMessage(c onst char *msg, const char *detail) fputs(msg, stderr);fputs(: , stderr);fputs(deta

15、il, stderr);fputc(n, stderr);exit(1);void DieWithSystemMessage(c onst char *msg) perror(msg);exit(1);/* 文件名:TCPServerUtility.c*/#in clude #in clude #in clude #in clude #in clude #in clude Practical.h static const int MAXPENDING = 5; / 常量不是宏定义int SetupTCPServerSocket(c onst char *service) struct addr

16、i nfo addrCriteria;memset (&addrCriteria, 0, sizeof(addrCriteria); / Zero out structureaddrCriteria.ai_family = AF_UNSPEC; addrCriteria.ai_flags = AI_PASSIVE; addrCriteria.ai_socktype = SOCK_STREAM; addrCriteria.ai_protocol = IPPROTO_TCP;struct addri nfo *servAddr; / List of server addressesint rtnV

17、al = getaddri nfo( NULL, service, &addrCriteria, &servAddr);if (rtnVal != 0)DieWithUserMessage(getaddri nfo() failed, gai_strerror(rt nV al);int servSock = -1;struct addri nfo *addr;for (addr = servAddr; addr != NULL; addr = addr-ai_ next)servSock = socket(addr-ai_family, addr-ai_socktype,addr-ai_pr

18、otocol);if (servSock ai_addr, addr-ai_addrlen) = 0) &(listen(servSock,MAXPENDING) = 0)struct sockaddr_storage localAddr; sockle n_t addrSize = sizeof(localAddr);if (getsock name(servSock, (struct sockaddr *) &localAddr, &addrSize) 0) DieWithSystemMessage(getsock name() failed);break;close(servSock);

19、servSock = -1;freeaddri nfo(servAddr);retur n servSock;int AcceptTCPC onn ectio n(i nt servSock)int clntSock; /*客户连接返回的套接字 */struct sockaddr_in echoClntAddr; /* 客户地址 */un sig ned int cln tLe n;cln tLe n = sizeof(echoCl ntAddr);/*等待客户端连接 */if (cl ntSock = accept(servSock, (struct sockaddr *) & echoCl

20、 ntAddr,&cln tLe n) 0) prin tf(accept() failed);exit(1);prin tf(Ha ndli ng clie nt %sn, i net_n toa(echoC In tAddr.s in _addr);retur n cln tSock;void HandleTCPClient(int clntSocket)char bufferBUFSIZE;ssize_t numBytesRcvd = recv(cl ntSocket, buffer, BUFSIZE, 0);if (nu mBytesRcvd 0)/将收到的信息返回给客户端if(se

21、nd(cl ntSocket, buffer, nu mBytesRcvd, 0) 0) DieWithSystemMessage(se nd() failed);nu mBytesRcvd = recv(cl ntSocket, buffer, BUFSIZE, 0);if (nu mBytesRcvd 0) DieWithSystemMessage(recv() failed);close(c In tSocket);/*文件名:AddressUtility.c*/#i nclude #in clude #in clude #in clude void Prin tSocketAddres

22、s(c onst struct sockaddr *address, FILE *stream) if (address = NULL | stream = NULL)return;void *nu mericAddress;char addrBufferINET6_ADDRSTRLEN;in _port_t port;switch (address-sa_family)case AF_INET: /IPV4nu mericAddress = &(struct sockaddr_ in *) address)-s in _addr; port = n tohs(struct sockaddr_

23、 in *) address)-s in _port); break;case AF_INET6: /IPV6nu mericAddress = &(struct sockaddr_ in6 *) address)-s in 6_addr; port = n tohs(struct sockaddr_ in6 *) address)-s in 6_port); break;default:fputs( unknown type, stream);return;if (inet_ntop(address-sa_family, numericAddress, addrBuffer, sizeof(

24、addrBuffer)=NULL)fputs(i nvalid address, stream); / Un able to convertelsefprin tf(stream, %s, addrBuffer); / 往流中写字符串if (port != 0)fprin tf(stream, -%u, port); u% 表示无符号整数输出bool SockAddrsEqual(c onst struct sockaddr *addr1, const struct sockaddr *addr2)if (addr1 = NULL | addr2 = NULL)retur n addr1 =

25、addr2;else if (addr1-sa_family != addr2-sa_family)return false;else if (addr1-sa_family = AF_INET)struct sockaddr_ in *ipv4Addr1 = (struct sockaddr_ in *) addr1;struct sockaddr_ in *ipv4Addr2 = (struct sockaddr_ in *) addr2;retur n ipv4Addr1-s in _addr.s_addr = ipv4Addr2-s in _addr.s_addr &ipv4Addr1

26、-s in_port = ipv4Addr2-s in _port;else if (addr1-sa_family = AF_INET6)struct sockaddr_i n6 *ipv6Addr1 = (struct sockaddr_i n6 *) addr1;struct sockaddr_i n6 *ipv6Addr2 = (struct sockaddr_i n6 *) addr2;retur n memcmp(&ipv6Addr1-s in 6_addr, &ipv6Addr2-s in 6_addr,sizeof(structin 6_addr) = 0& ipv6Addr1-si n6_port = ipv6Addr2-si n6_port;elsereturn false;/*文件名:TCPEchoServer-Thread.c*

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1