实验五多线程并发服务器编程Word文件下载.docx

上传人:b****5 文档编号:19508252 上传时间:2023-01-07 格式:DOCX 页数:14 大小:89.30KB
下载 相关 举报
实验五多线程并发服务器编程Word文件下载.docx_第1页
第1页 / 共14页
实验五多线程并发服务器编程Word文件下载.docx_第2页
第2页 / 共14页
实验五多线程并发服务器编程Word文件下载.docx_第3页
第3页 / 共14页
实验五多线程并发服务器编程Word文件下载.docx_第4页
第4页 / 共14页
实验五多线程并发服务器编程Word文件下载.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

实验五多线程并发服务器编程Word文件下载.docx

《实验五多线程并发服务器编程Word文件下载.docx》由会员分享,可在线阅读,更多相关《实验五多线程并发服务器编程Word文件下载.docx(14页珍藏版)》请在冰豆网上搜索。

实验五多线程并发服务器编程Word文件下载.docx

*******************************************************************/

#include<

stdio.h>

pthread.h>

//创建多线程

voidchildThread();

intmain()

{

inti=0;

pthread_tid;

pthread_create(&

id,NULL,childThread,NULL);

printf("

点击回车键结束运行\n"

);

getchar();

}

voidchildThread()

inti;

for(i=0;

;

{

childthreadsleep%d\n"

i+1);

sleep

(1);

}

编译链接多线程程序需要用到特殊的库文件libthread.so,而我们在以前的实验中的编译链接程序的方式使用的是标准库函数,不需要特别指定。

因此编译链接多线程的程序时必须使用–l选项,该选项后面直接跟库文件名称,但要去掉lib和后缀名,即–lthread。

注意-l是lib的首字母。

例如如果需要用到数学函数库libm.so则编译链接程序时需要使用选项–lm。

按以前实验方式编译该程序发现错误,图1中红色部分为错误信息,该信息表明链接程序未找到函数pthread_create的实现。

图2为编译正确的结果显示。

图1、未使用-lpthread选项链接错误

图2、正确使用-lpthread选项编译链接结果

2、多线程并发服务器编程

类似于多进程服务器编程,本实验的多线程并发服务器也分为两部分程序:

服务器程序和客户端程序。

其中客户端部分和实验一中的客户端部分是一致的,在本实验中我们作了简化;

请注意本实验中的客户端只是为了测试并发服务器的功能,它们本身并不属于多线程并发服务器的内容。

服务器部分实现了多线程的功能,父线程不断地(for循环)等待客户端的连接,一旦有客户端连接服务器,服务器则创建(pthread_create)一个子线程用于该客户端的接收数据处理。

在验证结果阶段可以同时启动多个客户端,注意服务器只需要启动一次。

显而易见的是随着客户端数量的增加,服务器子线程的数量也将线性增加,这必将加重服务器硬件资源(内存)的消耗,最终可导致服务器硬件资源耗尽而崩溃。

但与实验六中多进程并发服务器相比,对同等数量的多线程和多进程程序而言,多线程程序对内存的需求明显低于多进程程序。

本次实验中的客户端程序作了更多的简化,采用单文件方式。

客户端部分未用到多线程,其编译链接方法与以前的实验一致。

服务器部分仍然采用多文件方式,因此在编译运行时要用到多个C文件,注意编译时要加上–lthread选项。

分析、运行下列代码,建议由两位同学分别运行服务器和客户端,然后再转换角色分析程序。

1)客户端程序源码

/******************************************************************************

文件名:

TCPSimpleClient.c

描述:

一个简单的TCP客户端例子,发送helloworld给服务器,并接收服务器返回

******************************************************************************/

stdlib.h>

string.h>

unistd.h>

sys/types.h>

sys/socket.h>

netdb.h>

intmain(intargc,char*argv[])

if(argc!

=3)

使用方式必须为:

$>

命令服务器地址服务器端口号\n"

return1;

char*ip=argv[1];

char*port=argv[2];

intcs=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

if(cs<

0)

创建套接字失败\n"

return-1;

structsockaddr_inserv;

memset(&

serv,0,sizeof(serv));

serv.sin_port=htons(atoi(port));

inet_pton(AF_INET,ip,&

serv.sin_addr.s_addr);

serv.sin_family=AF_INET;

printf("

开始与服务器建立连接!

\n"

if(connect(cs,(structsockaddr*)&

serv,sizeof(serv))<

0)

连接失败!

连接成功!

charbuf[100]="

helloworld"

send(cs,buf,strlen(buf),0);

memset(buf,0,sizeof(buf));

recv(cs,buf,sizeof(buf)-1,0);

服务器返回信息:

%s\n"

buf);

close(cs);

return0;

2)服务器源码

服务器源码涉及四个C文件和一个头文件,各文件内容如下:

/*************************************************************************

Practical.h

***************************************************************************/

#ifndefPRACTICAL_H_

#definePRACTICAL_H_

stdbool.h>

voidDieWithUserMessage(constchar*msg,constchar*detail);

voidDieWithSystemMessage(constchar*msg);

voidPrintSocketAddress(conststructsockaddr*address,FILE*stream);

boolSockAddrsEqual(conststructsockaddr*addr1,conststructsockaddr*addr2);

intSetupTCPServerSocket(constchar*service);

intAcceptTCPConnection(intservSock);

voidHandleTCPClient(intclntSocket);

intSetupTCPClientSocket(constchar*server,constchar*service);

enumsizeConstants{

MAXSTRINGLENGTH=128,

BUFSIZE=512,

};

#endif//PRACTICAL_H_

/****************************************************************************

msg.c

*****************************************************************************/

voidDieWithUserMessage(constchar*msg,constchar*detail){

fputs(msg,stderr);

fputs("

:

"

stderr);

fputs(detail,stderr);

fputc('

\n'

exit

(1);

voidDieWithSystemMessage(constchar*msg){

perror(msg);

TCPServerUtility.c

arpa/inet.h>

#include"

Practical.h"

staticconstintMAXPENDING=5;

//常量不是宏定义

intSetupTCPServerSocket(constchar*service)

structaddrinfoaddrCriteria;

//Criteriaforaddressmatch

memset(&

addrCriteria,0,sizeof(addrCriteria));

//Zerooutstructure

addrCriteria.ai_family=AF_UNSPEC;

//Anyaddressfamily

addrCriteria.ai_flags=AI_PASSIVE;

//Acceptonanyaddress/port

addrCriteria.ai_socktype=SOCK_STREAM;

//Onlystreamsockets

addrCriteria.ai_protocol=IPPROTO_TCP;

//OnlyTCPprotocol

structaddrinfo*servAddr;

//Listofserveraddresses

intrtnVal=getaddrinfo(NULL,service,&

addrCriteria,&

servAddr);

if(rtnVal!

=0)

DieWithUserMessage("

getaddrinfo()failed"

gai_strerror(rtnVal));

intservSock=-1;

structaddrinfo*addr;

for(addr=servAddr;

addr!

=NULL;

addr=addr->

ai_next)

{

servSock=socket(addr->

ai_family,addr->

ai_socktype,addr->

ai_protocol);

if(servSock<

continue;

if((bind(servSock,addr->

ai_addr,addr->

ai_addrlen)==0)&

&

(listen(servSock,MAXPENDING)==0))

structsockaddr_storagelocalAddr;

socklen_taddrSize=sizeof(localAddr);

if(getsockname(servSock,(structsockaddr*)&

localAddr,&

addrSize)<

DieWithSystemMessage("

getsockname()failed"

break;

}

close(servSock);

servSock=-1;

freeaddrinfo(servAddr);

returnservSock;

intAcceptTCPConnection(intservSock)

intclntSock;

/*客户连接返回的套接字*/

structsockaddr_inechoClntAddr;

/*客户地址*/

unsignedintclntLen;

clntLen=sizeof(echoClntAddr);

/*等待客户端连接*/

if((clntSock=accept(servSock,(structsockaddr*)&

echoClntAddr,&

clntLen))<

accept()failed"

Handlingclient%s\n"

inet_ntoa(echoClntAddr.sin_addr));

returnclntSock;

voidHandleTCPClient(intclntSocket)

charbuffer[BUFSIZE];

ssize_tnumBytesRcvd=recv(clntSocket,buffer,BUFSIZE,0);

if(numBytesRcvd<

DieWithSystemMessage("

recv()failed"

while(numBytesRcvd>

0)

//将收到的信息返回给客户端

if(send(clntSocket,buffer,numBytesRcvd,0)<

send()failed"

numBytesRcvd=recv(clntSocket,buffer,BUFSIZE,0);

close(clntSocket);

/*****************************************************************************

AddressUtility.c

voidPrintSocketAddress(conststructsockaddr*address,FILE*stream)

if(address==NULL||stream==NULL)

return;

void*numericAddress;

charaddrBuffer[INET6_ADDRSTRLEN];

in_port_tport;

switch(address->

sa_family)

caseAF_INET:

//IPV4

numericAddress=&

((structsockaddr_in*)address)->

sin_addr;

port=ntohs(((structsockaddr_in*)address)->

sin_port);

break;

caseAF_INET6:

//IPV6

((structsockaddr_in6*)address)->

sin6_addr;

port=ntohs(((structsockaddr_in6*)address)->

sin6_port);

default:

fputs("

[unknowntype]"

stream);

if(inet_ntop(address->

sa_family,numericAddress,addrBuffer,sizeof(addrBuffer))==NULL)

[invalidaddress]"

//Unabletoconvert

else

fprintf(stream,"

%s"

addrBuffer);

//往流中写字符串

if(port!

=0)

fprintf(stream,"

-%u"

port);

//u%表示无符号整数输出

boolSockAddrsEqual(conststructsockaddr*addr1,conststructsockaddr*addr2)

if(addr1==NULL||addr2==NULL)

returnaddr1==addr2;

elseif(addr1->

sa_family!

=addr2->

sa_family)

returnfalse;

sa_family==AF_INET)

structsockaddr_in*ipv4Addr1=(structsockaddr_in*)addr1;

structsockaddr_in*ipv4Addr2=(structsockaddr_in*)addr2;

returnipv4Addr1->

sin_addr.s_addr==ipv4Addr2->

sin_addr.s_addr&

ipv4Addr1->

sin_port==ipv4Addr2->

sin_port;

}

sa_family==AF_INET6)

structsockaddr_in6*ipv6Addr1=(structsockaddr_in6*)addr1;

structsockaddr_in6*ipv6Addr2=(structsockaddr_in6*)addr2;

returnmemcmp(&

ipv6Addr1->

sin6_addr,&

ipv6Addr2->

sin6_addr,sizeof(structin6_addr))==0

&

ipv6Addr1->

sin6_port==ipv6Addr2->

sin6_port;

else

TCPEchoServer-Thread.c

void*ThreadMain(void*arg);

//线程块

structThreadArgs{

intmain(intargc,char*argv[])

if(argc!

=2)

运行命令和参数错误!

"

char*service=argv[1];

unsignedintprocessLimit=atoi(argv[2]);

intservSock=SetupTCPServerSocket

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

当前位置:首页 > 工程科技 > 纺织轻工业

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

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