西电2015网络程序设计大作业_第1页
西电2015网络程序设计大作业_第2页
西电2015网络程序设计大作业_第3页
西电2015网络程序设计大作业_第4页
西电2015网络程序设计大作业_第5页
已阅读5页,还剩28页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

西安电子科技大学

网络程序设计

班级:____________________________

姓名:

学号:

实验一:1.linux平台上的TCP并发服务

一'实验内容

掌握基本套接字函数使用方法、TCP协议工作原理、并发服务原理和编程方法。

实验内容:在linux平台上实现1个TCP并发服务器,至少可以为10个客户端同时提供

服务。

(1)基于TCP套接字编写服务器端程序代码,然后编译和调试;

(2)服务器程序要达到:可以绑定从终端输入的IP地址和端口;可以显示每一个进程

的进程号;可以显示当前并发执行的进程数量;可以根据客户机要求的服务时间确定

进程的生存时间。

(3)基于TCP套接字编写客户端程序代码,然后编译和调试;

(4)客户端程序要达到:可以从终端输入服务器的IP地址和端口;可以从终端输入对

服务器的服务时间要求。

(5)联调服务器和客户端,服务器每收到一个连接就新建一个子进程,在子进程中接收客

户端的服务时间请求,根据所请求的时间进行延时,然后终止子进程。如:客户端请

求服务10s,则服务器的子进程运行10s,然后结束。

(6)服务器要清除因并发服务而产生的僵尸进程。

二、分析及设计

要实现并发的服务器,也就是要求在同一段时间内,服务器能处理多个不同的客户端的请

求,并且要区分出它们各自差别,然后做到区别对待——这里只要用各自的进程的fd来区分各

自的身份。

不过这里因为水平有限,没有实现各个客户端各自定一个服务时间,服务时间是按照客户

端连接到退出的这段时间,也就是要客户端主动退出。

三'详细实现

服务器端:负责接收客户端的信息,然后在区分各个客户端的前提下,将

信息复述出来。

♦defineSERVERIP"127.0.0.1"

#defineSERVER[PORT8000

#defineMAXRECVLEN1024//发送信息的最大长度

#defineMAX[CLI函TNUM30//并发数量

#defineBACKLOG20//等待队列

以下是各种参数的初始定义;

intsockfd=-1;//套接字文件描述符

intret=-1;

structsockaddrinservaddr;//服务器地址

structsockaddrincliaddr;//客户端地址

socklentservaddrten=0;

socklentcliaddrTen=0;

intclientfdlMAXCLIENTNUM];//客户端队列,用于区分各个客户端,并区分服务

charrecvbuf[MAXRECVLEN];//缓冲区

intnewconnfd=-1;〃新进程的fd

inti=0;

intmaxfd=-1;

intnum=-1;

structtimevaltimeout;

生成服务端进程套接字及初始化;

sockfd=socket(AFINET,SOCKSTREAM,0);〃生成TCP/IP协议的套接字

if(sockfd<0)

(

perror("Failtosocket");〃套接字生成失败

exit(l);

)

servaddr.sinfamily=AFINET;〃TCP/IP协议族

servaddr.sinport=htons(SERVERPORT);〃湍口号,8000

servaddr.sinaddr.saddr=inetaddr(SERVERIP);〃格式化(本地)IP地址

调用bind。和listen。函数来绑定套接字地址和句柄以及坚挺服务请求;

servaddrlen=sizeof(servaddr);

if(bind(sock_fd,(structsockaddr♦)&servaddr,servaddrlen)<0)〃绑定套接字地址和句柄

(

perror(-ailto);

exit(l);

}

if(listen(sockfd,BACKLOG)<0)〃调用listen。

{

perror("Failtolisten);

exit(l);

}

select。函数可以设置超时,是长期没有文件描述符就绪时,进程可以跳出阻塞状态;

selectreadset=readset;

ret=select(maxfd+1,&selectreadset,NULL,NULL,&timeout);

〃设置超时,当长期系有文件描述符就绪跳出雨塞状态

之后的各种情况跳转判断,请看附录的详细代码

客户端:

各种参数以及初始化,因为客户端逻辑功能较少,因此参数的个数也不及服务器端的多;

intsockfd=-1;

intret=-1;

structsockaddrinservaddr;

structsockaddrincliaddr;|

socklentservaddrlen=0;

调用connect。函数,将该套接字和服务器套接字相连接;

if(connect(sockfd,(structsockaddr*)&servaddr,servaddrlen)<0)

{

perror("Failtoconnect);

exit(l);

从命令行读入信息;

num=read(STDINFILENO,buf,MAXRECVLEN);

其余代码见附录。

四'实验结果

TermlnaTerminalFileEditviewSearchTerminalHelp»*-(•))21:11

尸'rene$)rene-vlrtuat-machine:-/networkProgrammlng/1[。•€)rene@irene-vlrtual-fnochine:"/networkProgr«mmlng/1

vJIRectrvecllentO)dat«

rene9rene-virtual-nachtne:"/networkProgramtng/lS./Client.exe

Data:“don»here|first

|buf:first

No.4clientconesexit

timeoutbuf:exit

Recteye-1(5)datq

Data:[ICOMheretoo]Clientexit

rene9rene-virtual-nachtne:"/networkPrograrviing/l$./Client.exe

•Icoi^ehere,too

timeout:buf:|iconeheretoo-]

Rectevecllent(S)data

Data:exitjexlt

jbuf:exit

Hcitent(S)exit[Clientexit

URectevecltent(4)data;rene^rene-vtrtual-iwchine:-/networkProgranHt.ng/l$口

Data:exit

Cltent(4)exit

ttneout

;rcnejrcne•virtual-nachlne:-/networkProgratwlng/IS./Client.exe

,second

buf:second

buf:exit

Clientexit

reneJrene-vlrtual-iMchtne:~/networkProflraRHtng/l$./Client.exe

Icomehere

buf:]IcoweKre[

exit

buf:exit

Clientexit„

实验二:进程间的协调通信

—'实验内容

掌握进程的概念、进程间通信的基本原理、集成间通信的主要类型和各自的特点。实验内

容:在linux平台上实现1个父进程、2个子进程,利用管道和共享内存实现两个子进程之

间数据快速传送。

(1)创建一个进程,再创建一对管道、一块共享内存(大于64kB);

(2)通过fork()函数生成2个子进程;

(3)调试程序,确定父、子进程之间可以双向通信;

(4)调试程序,确定两个子进程之间可以通过父进程中转实现双向通信;

(5)调试程序,确定两个子进程都可访问共享内存;

(6)实现两个子进程之间无冲突地访问共享内存。传送的数据块不小于32kB,为了能够看

到演示效果,读/写每个字节后都延时0.5ms。

二、分析及设计

管道:

管道又可以分为无名管道和命名管道,两者的用途是不一样的。无名管道PIPE:主要

用于具有亲缘关系的进程之间的通信,无名管道的通信是单向的,只能由一段到另外一段;

无名管道是临时性的,完成通信后将自动消失。一般采用先创建无名管道,再创建子进程,

使子进程继承父进程的管道文件描述符,从而实现父子进程间的通信;在非亲缘关系管道之间,

如果想利用无名管道进行通信,则需要借助另外的文件描述符传递机制。

有名管道FIFO:有名管道是一个实际存在的特殊文件,利用有名管道可以实现同主机

任意进程之间的数据交互。

这里只需要无名管道,它只能在父子进程间传递信息,因此要求在两个子进程之间通信,必

须以父进程为媒介,进程1将信息传给父类,然后由父类将信息传给进程2,以此来完成两子

进程的一次通信。

共享内存:

通常由一个进程创建,其余进程对这块内存区进行读写。得到共享内存有两种方式:

映射/dev/mem设备和内存映像文件。前一种方式不给系统带来额外的开销,但在现实中并

不常用,因为它控制存取的是实际的物理内存;常用的方式是通过shmXXX函数族来实现

共享内存:

如果一个进程通过fork创建了子进程,则子进程继承父进程的共享内存,既而可以直

接对共享内存使用,不过子进程可以自身脱离共享内存。

基于共享内存的通信,不需要父进程的帮助,只要将两个子进程与申请的进程块联系起来即

可;主要的问题是两个子进程之间访问共享内存的互斥问题,必须等进程1写完内存后,

进程2才能读取,顺序不能乱。这里其实又设计到了进程通信的另一种方式——信号量,不过

这不是重点,因此只采用了最简单的方式,设置一把锁,然后两个子进程循环检查这个标志锁,

然后根据锁来决定是否就可以实现这个功能。

以下是共享内存的原理示意图:

进程A进程B

三'详细实现

管道:

intpl[2],p2[2];〃两个管道

intpidl,pid2;〃用于区分两个进程

char*str="HelioWorld";

charbufl[128],buf2[128];//绿冲区

memset(bufl,\0,128);〃初始化

memset(buf2,\c,128);

调用pipe()来生成管道:

if(pipe(pl)=-1)〃生成管道

{

printf("functionpipe()callsfailed.");

return-1;

调用fork。创建一个子进程,并实现数据写入到父进程中:

if((pidl=fork())=-1)//创建一个子进程

{

printf("functionfork()callsfailed.\n");

return-1;

}elseif(pidl=0)〃在子进程1中

(

printf("Inchildl:pid=%d\n",getpid());

write(pl[l],str,strlen(str));//向无名管道中写入str

}else{//在父进程中

printf("Infather:pid=d\n",getpid());

read(pl[0],bufl,strlen(str));//读取无名管道

printf("Infather:buf=%s\n"fbufl);

write(p2[l],bufl,strlen(str));

其余代码略;

共享内存:

ffdeftneTEXT_SZ1024*60〃缓存区大小

void*shm=NULL;〃分配的共享内存的原始首地址

structshared_use_st*shared=NULL;

intshmtd;〃共享内存标识符

定义一个结构体:

structshared_use_st

{_

tntwritten;〃作为一个标志,1表示可读,。表示可写

chartext[TEXT_SZ];〃记录写入和读取的文本

创建一个共享内存并且将之连接到当前进程的地址空间:

〃创建共军内存一

shmtd=shmget((key_t)1234,stzeof(structshared_use_st),0666|IPC_CREAT);

if(shmid==-1)

(

fprtntf(stderr,"shmgetfatled\nM);

extt(EXIT_FAILURE);

〃将共享内存连接到当前进程的地址空间

shm=shmat(shmid,0,0);

shared=(structshared__use_st*)shm;

shared->wrttten=0;

printf(n\nMenoryattachedat%X\n".(tnt)shm);

一个进程负责内存写入:(读进程类似)

pidl=fork();〃写进程

if(pidl==0){

if(shm==(void*)-l)

(

fprtntf(stderr,"shmatfatled\n");

exit(EXIT_FAILURE);a

)

Process_Wrtte();

Process_Write()和Process_Read()代码偏长,详见附录;

四'实验结果

管道:

rene(O)rene-virtual-machine:~/networkProgrammlng/2

rene@rene-virtual-machine:-/networkProgrammtng/2$./Pipec

Infather:pid=28121

Inchildl:pid=28122

Infather:buf=HelloWorld

Inchtld2:ptd=28123

Inchild?:buf=HelloWorld

•renegrene-virtual-machine:-/networkProgramming/2$!

共享内存:

rene@rene-virtual-machine:-/networkProgramming/2$./SharedMemory.exe

Memoryattachedat73ACBO00

Entersometext:Howareyou?

/ouwrote:Youwrote:Howareyou?

Matting.・,

batting.,,

Matting.,・

Entersometext:Iamfine.

/ouwrote:Youwrote:Youwrote:Youwrote:Iamfine.

Waiting・・・

Waiting

Entersometext:

其实可以看到进程间运行还是有些问题,Youwrote多次出现。这个问题需要跟完善的信号

操作来实现完全的按序执行。

实验三:Windows平台上的TCP并发服务

—'实验内容

编程内容与实验1相同,操作系统为windows。了解Windows与Linux平台编程环境的差

异,掌握Winsock编程接口及编程方法。

二'分析及设计

Berkeley套接字刚开始时4.2BSDUnix操作系统(与1983年发布)的一套应用程序接口,

设计之初就是为了实现TCP/IP协议。Berkeley套接字应用程序接口形成了事实上的网络套接

字的标准。

而微软当时为了迅速占据市场以及招聘人才,全盘套用了Unix的网络编程实现,其中

就包括了Berkeley套接字。不过由于Unix和Windows的内核实现是有差别的,Berkeley套接字

在Windows上的运行效率并不高,因此后来Windows推出了Winsock,并且为了预防AT&T

申请专利,它被实现为一个与网络协议无关的网络编程接口.

Winsock的实现一般在Berkeley套接字函数上加了前缀WSA用以区分。

这个实验的具体实现其实和实验1没有实质上的区别,差别在于同样的功能要用不同

的函数来实现。

这个程序实现的比较简单,服务器和客户端只有一次交换信息。

三'具体实现(具体阐述与linux的异同)

服务器端:

windwows下的socket编程函数库:

#pragmacomment(lib,“WS232.lib")

各个参数及初始化:

"VSADATAwsaData;

WORDsockVersion=MAKEWORD⑵2);windo$s网络编程库的版本号信息,最新是2.2

SOCKETsListen=0;/,TCP通信的socket数据结构

sockaddr_insin={0};创建一个socket编程类型的网络地址数据结构:

sockaddr_inremoteAddr={0};创建一个socket编程类型的网络地址数据结构:

〃讦地址布端口号

charszTextL]="TCPServerDemo”;

intnAddrLen=0:

不同之处:

//initwsa

if(WSAStartup(sockVersion,ftwsaData)!=0)WSAStartup函数是在程序中初始化并加载Windows网络

编程库的ws2_32.dll动态库文件°

(

cout«*initlizationfailed!*«endl;

exit(O);/如果WSAStartup返回值为1的话就表示ws2_32.dll文件有问题,程序退出

同样是bind()Jisten():

if(bind(sListen,(LPSOCKADDR)&sin,sizeof(sin))==SOCKET_ERROR)

cout«”bindfailed!*«endl;

return0:如果socket绑定失败返回程序。并退出程序

)

if(listen(sListen,2)==SOCKET.ERROR)listen是用来打开本地计算机的端口,参数2表示客户端同

,/时连接服务器的数量.这里是说可以同时有2个客户端连接

〃到本机打开的端口

{

cout«”listenfailed!*<<endl;

return0;/如果打开本地端口失败就返回。并退出程序

)

其余代码略;

客户端:

WSADATAwsaData;

WORDsockVersion=MAKEWORD(2,2);

SOCKETsock=0:

connect。函数:

〃初始化socket并连接远程计算机

if(connect(sock,(sockaddr*)&sin,sizeof(sockaddr))==-1)

(

cout<<"connectfailed!”«endl;

return0;〃连接失败就返回0到程序

)

使用完函数库,需要释放:

WSACleanup();〃释放ws2_32.dll动态库

四'实现结果

解决方2

心得体会:

网络程序设计这门课是一门非常非常实用的课,可惜开课的时间不太合适,刚开始时,

网络方面的知识实在是非常的欠缺,因此现在看来非常基础的socket,在那时是根本无法理解

的,而后来随着课程的推进,各种实验上机接踵而来,也无法抽出时间来好好学习网络编程,浪

费了很多时间,这让我感到很可惜,错过了学习这门课的最好时候。

不过在这一段时间的补充学习,我还是追回来一点内容,至少不是两眼一蒙,不会啥

都不认识了。Winsock的内容继承了Windows编程的一贯特点,艰涩难懂——至少对于还没入

门的我是这种感觉的。

强烈希望能够网络程序这门课放到大三下学期!

附录:

实验一:

服务器端:

#include<stdio.h>

ttinclude<stdlib.h>

#include<string.h>

#include<sys/time.h>

#include<sys/types.h>

^include<sys/socket.h>

#include<netinet/in.h>

Winclude<sys/select.h>

#include<errno.h>

♦♦defineSERVER_IP"127.0.0.r

#defineSERVER_P0RT8000

^defineMAX_RECV_LEN1024〃发送信息的最大长度

^defineMAX_CLIENT_NUM30〃并发数量

ttdefineBACK_L0G20〃等待队列

staticintrunning=1;

intmain(intargc,char*argv[])

intsockfd=7;〃套接字文件描述符

intret=-1;

structsockaddrinservaddr;〃服务器地址

structsockaddr_incli_addr;〃客户端地址

socklen_tserv_addr_len=0;

socklen_tcli_addr_len=0;

intclient_fd[MAX_CLIENT_NUM];〃客户端队列,用于区分各个客户端,并区分服务

charrecvbuf[MAXRECVLEN];〃缓冲区

intnew_conn_fd=T;〃新进程的fd

inti=0;

intmax_fd=-1;

intnum=-1;

structtimevaltimeout;

fd_setread_set;

fd_setwrite_set;

fd_setselect_read_set;

FD_ZER0(&read_set);

FDZERO(&writeset);

FDZER0(&selectreadset);

for(i=0;i<MAX_CLIENT_NUM;i++)

(

client_fd[i]=-1;〃初始化

)

memset(&serv_addr,0,sizeof(servaddr));〃初始化

memset(&cli_addr,0,sizeof(cli_addr));

sock_fd=socket(AF_INET,SOCK_STREAM,0);〃生成TCP/IP协议的套接字

if(sock_fd<0)

(

perror(,zFailtosocket");〃套接字生成失败

exit(1);

)

serv_addr.sin_family二AF_INET;〃TCP/IP协议族

serv_addr.sin_port=htons(SERVER_PORT);//端口号,8000

serv_addr.sin_addr.s_addr=inet_addr(SERVERIP);〃格式化(本地)IP地址

unsignedintvalue=1;

if(setsockopt(sock_fd,S0L_S0CKET,SO_REUSEADDR,

(void*)fevalue,sizeof(value))<0)

(

perror(""Failtosetsockopt");

exit(1);

)

serv_addr_len=sizeof(serv_addr);

if(bind(sock_fd,(structsockaddr*)&serv_addr,serv_addr_len)<0)〃绑定

套接字地址和句柄

perror(,zFailtobind");

exit⑴;

}

if(listen(sock_fd,BACK_LOG)<0)〃调用listen。

(

perror(z,Failtolisten");

exit(1);

}

charbuf[1024];

max_fd=sock_fd;

intlen;

FDSET(sock_fd,&read_set);

while(running)

(

timeout.tv_sec=5;〃等待时间

timeout,tvusec=0;

max_fd=sock_fd;

for(i=0;i<MAX_CLIENT_NUM;i++)

(

if(max_fd<client_fd[i])

[

max_fd=client_fd[i];

I

}

select_read_set=read_set;

ret=select(max_fd+1,&select_read_set,NULL,NULL,&timeout);〃设

置超时,

〃当长期没有文件描述符就

绪时,跳出阻塞状态

if(ret=0)〃队列为空

(

printf(,ztimeout\n,z);

)

elseif(ret<0)//出错

(

printf(,zerroroccur\n,z);

)

else

(

if(FD_ISSET(sock_fd,&select_read_set))

{

printf("newclientcomes\n〃);

len=sizeof(cli_addr);

newconnfd=accept(sockfd,(structsockaddr*)&cliaddr,&len);

if(new_conn_fd<0)

(

perror(z,Failtoaccept");

exit(1);

}

else

(

for(i=0;i<MAX_CLIENT_NUM;i++)

(

if(client_fd[i]==-1)

(

client_fd[i]=newconnfd;

FD_SET(new_conn_fd,&read_set);

break;

if(maxfd<newconnfd)

(

max_fd=new_conn_fd;

)

)

)

)

else

I

for(i=0;i<MAX_CLIENT_NUM;i++)

(

memset(recv_buf,0,MAX_RECV_LEN);

if(FDISSET(clientfd[i],feselectreadset))

(

num=read(c1ient_fd[i],recv_buf,MAX_RECV_LEN);

if(num<0)

(

printf(^Client(%d)left\nz/,client_fd[i]);

FD_CLR(c1ient_fd[i],&read_set);

close(clientfd[i]);

clientfd[i]=-1;

)

elseif(num>0)

(

recv_buf[num]='\0';

printf(^Recieveclient(%d)data\n〃,client_fd[i]);

〃输出服务器fd

printf("Data:%s\n\n,/,recv_buf);

〃输出信息

}if(num==0)

printf("Client(%d)exit'rT,client_fd[i]);

FD_CLR(client_fd[i],&read_set);

close(clientfd[i]);

client_fd[i]=-1;

)

)

}

)

}

)

return0;

)

客户端:

^include<stdio.h>

#include<stdlib.h>

#include<string.h>

^include<unistd.h>

#include<sys/time.h>

#include<sys/types.h>

#include<sys/socket.h>

ttinclude<netinet/in.h>

#include<sys/select.h>

#defineSERVER_IP〃127.0.0.1〃

ttdefineSERVERPORT8000

^defineMAX_RECV_LEN1024

staticintrunning=1;

intmain(intargc,char*argv[])

(

intsock_fd=-1;

intret=T;

structsockaddr_inserv_addr;

structsockaddrincliaddr;

socklen_tserv_addr_len=0;

memset(&servaddr,0,sizeof(servaddr));

sock_fd=socket(AF_INET,S0CK_STREAM,0);

if(sock_fd<0)

(

perror(,/Failtosocket");

exit(1);

)

servaddr.sin_family=AFINET;

serv_addr.sin_port=htons(SERVERPORT);

servaddr.sinaddr.saddr=inetaddr(SERVERIP);

serv_addr_len=sizeof(serv_addr);

if(connect(sock_fd,(structsockaddr*)&serv_addr,serv_addr_len)<0)〃与

服务器套接字相连接

(

perror(""Failtoconnect");

exit(1);

}

charbuf[1024];

intnum=0;

while(running)

(

num=read(STDIN_FILENO,buf,MAX_RECV_LEN);

if(num>0)

(

buf[num]=,\0,;

printf(,zbuf:%s\n〃,buf);

num=write(sock_fd,buf,num);

if(num<0)

printf("writefailed\n〃);

exit(1);

I

if(strncmp(buf,"exit”,strlen(,,exit,/))==0)

[

printf("Clientexit\n");

close(sockfd);

return0;

}

)

)

return0;

)

实验二:

管道:

#include<stdio.h>

#include<unistd.h>

#include<string.h>

intmain()

(

intpl[2],p2[2];〃两个管道

intpidl,pid2;〃用于区分两个进程

char*str=,/HelloWorld,/;

charbuf1[128],buf2[128];//缓冲区

memset(bufl,*\0J,128);//初始化

memset(buf2,J\0,,128);

if(pipe(pl)==-1)〃生成管道

(

printf(/zfunctionpipe()callsfailed.,z);

return-1;

)

if(pipe(p2)==-1)

printf(^functionpipeOcallsfailed.z/);

return-1;

)

if((pidl=fork())==-1)〃创建一个子进程

(

printf(''functionfork()callsfailed.\nz,);

return-1;

Jelseif(pidl=0)//在子进程1中

(

printf(,zInchildl:pid=%d\n,z,getpidO);

write(pl[1],str,strlen(str));〃向无名管道中写入str

}else{〃在父进程中

printf(,zInfather:pid=%d\nz,,getpidO);

read(pl[0],bufl,strlen(str));〃读取无名管道

printf(,zInfather:buf=%s\n,z,buf1);

write(p2[l],buf1,strlen(str));

)

if((pid2=fork())==-1)〃创建一个子进程

(

printf(''functionfork()callsfailed.\n,z);

return-1;

}elseif(pid2=0)〃在子进程2中

(

read(p2[0],buf2,strlen(str));

printf(z,Inchild2:pid=%d\n,z,getpid());

printf(,zInchild2:buf=%s\n,z,buf2);

共享内存:

ttinclude<unistd.h>

^include<stdlib.h>

#include<stdio.h>

^include<sys/ipc.h>

#include<sys/shm.h>

#defineTEXTSZ1024〃缓存区大小

void*shm=NULL;〃分配的共享内存的原始首地址

structshared_use_st"shared=NULL;

intshmid;〃共享内存标识符

structshareduse_st

(

intwritten;〃作为一个标志,1表示可读,。表示可写

chartext[TEXTSZ];〃记录写入和读取的文本

);

intmain()

(

intpidl,pid2;

〃创建共享内存

shmid=shmget((key_t)1234,sizeof(structshared_use_st),0666IPC_CREAT);

if(shmid==-1)

fprintf(stderr,“shmgetfailed'n");

exit(EXIT_FAILURE);

)

〃将共享内存连接到当前进程的地址空间

shm=shmat(shmid,0,0);

shared=(structshared_usest*)shm;

shared->written=0;

printf('\nMemoryattachedat%X\nz,,(int)shm);

pidl=forkO;〃写进程

if(pidl==0){

if(shm==(void*)-l)

(

fprintf(stderr,/zshmatfailed'n");

exit(EXIT_FAILURE);

}

Process_Write();

)

pid2=forkO;〃读进程

if(pid2==0){

if(shm==(void*)-l)

(

fprintf(stderr,“shmatfailed'n");

exit(EXIT_FAILURE);

)

Process_Read();

)

return0;

voidProcessRead(){

while(l)〃读取共享内存中的数据

(

//没有进程向共享内存定数据有数据可读取

if(shared->written!=0)

(

printf(/zYouwrote:%s”,shared->text);

sleep(rand()%3);

〃读取完数据,设置written使共享内存段可写

shared->written=0;

〃输入了end,退出循环(程序)

if(strncmp(shared->text,"end”,3)—0)

break;

}

else〃有其他进程在写数据,不能读取数据

sleep(l);

)

〃把共享内存从当前进程中分离

if(shmdt(shm)==-1)

(

fprintf(stderr,“shmdtfailed'n");

exit(EXIT_FAILURE);

)

〃删除共享内存

if(shmctl(shmid,IPCRMID,0)==-1)

fprintf(stderr,shmctl(IPC_RMID)failed"");

exit(EXIT_FAILURE);

)

exit(EXIT_SUCCESS);

)

voidProcess_Write(){

〃设置共享内存

charbuffer[BUFSIZ+1];〃用于保存输入的文本

while(l)〃向共享内存中写数据

(

〃数据还没有被读取,则等待数据被读取,不能向共享内存中写入文本

while(shared->written==1)

(

sleep(l);

printf("Waiting...\n");

)

〃向共享内存中写入数据

sleep(2);

printf("Entersometext:");

fgets(buffer,BUFSIZ,stdin);

strncpy(shared->text,buffer,TEXTSZ);

〃写完数据,设置written使共享内存段可读

shared->written=1;

〃输入了end,退出循环(程序)

if(strncmp(buffer,"end",3)==0)

break;

}

〃把共享内存从当前进程中分离

if(shmdt(shm)==-1)

fprintf(stderr,“shmdtfailed\n〃);

exit(EXIT_FAILURE);

sleep(2);

exit(EXIT_SUCCESS);

实验三:

服务器端:

#include<iostream>

#include<stdio.h>

^include<windows.h>〃一定要包含该头文件

usingnamespacestd;

#pragmacomment(lib,“WS232.lib")〃windwows下的socket编程函数库

intmain()

(

WSADATAwsaData;

WORDsockVersion=MAKEWORD(2,2);//windows网络编程库的版本号信息,最新是2.2

SOCKETsListen=0;〃TCP通信的socket数据结构

sockaddrinsin={0};〃创建一个socket.编程类型的网络地址数据结构

这个用于本地

sockaddr^inremoteAddr={0};〃创建一个socket编程类型的网络地址数据结构

这个用于储存远程主机的

〃IP地址和端口号

charszText[]="TCPServerDemo”;

intnAddrLen=0;

nAddrLen=sizeof(sockaddrin);〃计算这个sockaddrin数据结构的大小

//fillsin

sin.sin_port=htons(4567);〃设置本地(这里指服务端)计算机要打开的端口

sin.sin_family=AF_INET;〃设置网络通信的网络协议族类型

sin.sin_addr.S_un.S_addr=INADDR_ANY;〃设置本地计算机的IP地址,一般INADDR_ANY

在程序运行时

〃会自动计算成本地的1P地址的

//initwsa

if(WSAStartup(sockVersion,&wsaData)!=O)〃WSA$tartup函数是在程序中初始化并加

载Windows网络

〃编程库的ws2_32.dll动态库文件。

(

cout«”initlizationfailed!zz<<endl;

exit(O);〃如果WSAStartup返回值为1的话就表示ws2_32.dl1文件有问题,程序退出

)

sListen=socket(AFINET,SOCK_STREAM,IPPROTO_TCP);〃在本机上创建一个socket

〃使用bind函数绑定本机的ip和打开端口到本机创建的socket结构上,并初始化该socket

〃重点说明-•个在服务器上是用bind函数来初始化socket,在客户机上是用connect函数来

初始化socket的喔

if(bind(sListen,(LPSOCKADDR)&sin,sizeof(sin))==SOCKETJRROR)

(

cout«”bindfailed!”«endl;

return0;〃如果socket绑定失败返回程序0并退出程序

)

if(listen(sListen,2)==SOCKET_ERROR)“listen是

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论