实验一基于TCP套接字的文件传输客户服务器程序设计实验报告.docx
《实验一基于TCP套接字的文件传输客户服务器程序设计实验报告.docx》由会员分享,可在线阅读,更多相关《实验一基于TCP套接字的文件传输客户服务器程序设计实验报告.docx(15页珍藏版)》请在冰豆网上搜索。
实验一基于TCP套接字的文件传输客户服务器程序设计实验报告
2011年秋季学期《计算机网络II》实验报告
考核科目:
计算机网络II
学生所在院(系):
计算机科学与技术学院
学生所在学科:
姓名:
学号:
实验时间:
2011年11月29日
一、问题描述
1.实验名称:
基于TCP套接字的文件传输客户服务器程序设计
2.实验目的:
掌握基于TCP套接口的网络程序设计。
掌握大规模文件传输的基本方法。
3.实验要求:
服务器程序分别实现迭代服务器,并发服务器,使用单进程和select的TCP服务器。
服务器在客户提出请求后向客户发送一个不小于1M大小的文件。
二、概要设计
1.客户程序概要设计。
创建TCP套接口;
指定服务器IP地址和端口;
建立与服务器的连接;
向服务器发送请求传送文件的请求“hello”;
接受服务传输过来的数据;
终止程序。
2.迭代服务器概要设计。
创建TCP套接口;
捆绑服务器众所周知端口到套接口;
把套接口变成监听套接口;
接受客户连接;
读取客户的请求,发送应答;
终止连接并等待下一个客户连接。
3.并发服务器概要设计。
创建TCP套接口;
捆绑服务器众所周知端口到套接口;
把套接口变成监听套接口;
接受客户连接;
调用fork()派生子进程处理连接,父进程等待新的连接请求并处理结束的子进程;
子进程读取客户的请求,发送应答,数据传输结束后终止连接并退出。
4.使用单进程和select的TCP服务器概要设计。
创建TCP套接口;
捆绑服务器众所周知端口到套接口;
把套接口变成监听套接口;
调用select初始化数据结构;
阻塞于select;
若监听套接字变为可读,accept新的连接;
检查现有连接,若连接可读则读取客户请求,发送应答,数据传输结束后关闭当前连接并更新数据结构。
三、详细设计
1.客户程序详细设计。
a)主要数据结构设计
ipv4套接字地址结构
structin_addr{
in_addr_ts_addr;
};
structsockaddr_in{
uint8_tsin_len;
sa_family_tsin_family;
in_port_tsin_port;
structin_addrsin_addr;
charsin_zero[8];
};
字符数组
charbuf[MAXSIZE];
b)主要函数功能
socket(),connect(),writen(),readn(),close()
intsocket(intdomain,inttype,intprotocol);
指定期望的通信协议类型。
返回值:
成功则为非负描述符,出错则为-1。
intconnect(intsockfd,conststructsockaddr*addr,socklen_taddrlen);
tcp客户用connect函数来建立与tcp服务器的连接。
ssize_treadn(intfd,void*vptr,size_tn);
从一个描述字读n个字节到vptr所指的缓冲区。
ssize_twriten(intfd,constvoid*vptr,size_tn);
从vptr所指的缓冲区中写n个字节到一个描述字。
intclose(intfd);
关闭描述字。
2.迭代服务器详细设计。
a)主要数据结构设计
ipv4套接字地址结构(略)
字符数组
charbuf[MAXSIZE];
b)主要函数功能
socket(),bind(),listen(),accept(),writen(),readn(),close()
intbind(intsockfd,conststructsockaddr*addr,socklen_taddrlen);
bind函数把一个本地协议地址赋予一个套接字。
对于网际网协议,协议地址就是32位的ipv4地址或者128位的ipv6地址与16位的tcp或udp端口号的组合。
如果一个tcp客户或者服务器未曾调用bind捆绑一个端口,当调用connect或listen时,内核就要为相应的套接字选择一个临时的端口。
intlisten(intsockfd,intbacklog);
listen函数把一个未连接的套接字转换成一个被动的套接字,指示内核接受指向该套接字的连接请求。
intaccept(intsockfd,structsockaddr*addr,socklen_t*addrlen);
accept函数由tcp服务器调用,用于从已完成连接的队列队头返回下一个已完成连接。
如果已完成连接的队列为空,那么进程被投入睡眠。
3.并发服务器详细设计。
a)主要数据结构设计
ipv4套接字地址结构(略)
字符数组
charbuf[MAXSIZE];
b)主要函数功能
socket(),bind(),listen(),accept(),witen(),readn(),signal(),close()
typedefvoidSigfunc(int);
Sigfunc*signal(intsigno,Sigfunc*func);
调用函数func处理信号signo。
4.使用单进程和select的TCP服务器详细设计。
a)主要数据结构设计
ipv4套接字地址结构(略)
字符数组
charbuf[MAXSIZE];
b)主要函数功能
socket(),bind(),listen(),accept(),writen(),readn(),select(),
FD_SET(),FD_ISSET(),close()
intselect(intnfds,fd_set*readfds,fd_set*writefds,
fd_set*exceptfds,structtimeval*timeout);
voidFD_CLR(intfd,fd_set*set);
intFD_ISSET(intfd,fd_set*set);
voidFD_SET(intfd,fd_set*set);
voidFD_ZERO(fd_set*set);
select()函数允许进程指示内核等待多个事件中的任意一个发生,并仅在一个或者多个事件发生或经过某指定的时间后才唤醒进程。
FD_CLR()清除描述字fd相应位;
FD_ISSET()测试描述字fd相应位;
FD_SET()在描述字集合中为fd设置相应位;
FD_ZERO()初始化描述字集合。
四、实验结果
迭代服务器
并发服务器
使用单进程和select的TCP服务器
五、心得体会
未知的事情总显的神秘,以前一直认为在网络中传输数据是很复杂的事情。
对“套接字”也只是有个泛泛的概念,知道网络编程要也能够到这个。
接触以后,感觉最基本的套接字编程还是挺简单的。
但是考虑到各种有可能发生的情况之后,程序就变得复杂了。
六、附录:
(数据结构、核心代码)
/*myfunc.h*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#defineSERV_PORT9996
#defineMAXSIZE1024
typedefvoidSigfunc(int);
ssize_treadn(intfd,void*vptr,size_tn)
{
ssize_tnleft;
ssize_tnread;
char*ptr;
ptr=vptr;
nleft=n;
while(nleft>0){
if((nread=read(fd,ptr,nleft))<0){
if(errno==EINTR)
nread=0;
else
return(-1);
}elseif(nread==0)
break;
nleft-=nread;
ptr+=nread;
}
return(n-nleft);
}
ssize_twriten(intfd,constvoid*vptr,size_tn)
{
size_tnleft;
ssize_tnwritten;
constchar*ptr;
ptr=vptr;
nleft=n;
while(nleft>0){
if((nwritten=write(fd,ptr,nleft))<=0){
if(errno==EINTR)
nwritten=0;
else
return(-1);
}
nleft-=nwritten;
ptr+=nwritten;
}
return(n);
}
voidsig_chid(intsigno)
{
pid_tpid;
intstat;
while((pid=waitpid(-1,&stat,WNOHANG))>0){
printf("child%dterminated\n",pid);fflush(stdout);}
return;
}
Sigfunc*signal(intsigno,Sigfunc*func)
{
structsigactionact,oact;
act.sa_handler=func;
sigemptyset(&act.sa_mask);
act.sa_flags=0;
if(signo==SIGALRM){
#ifdefSA_INTERRUPT
act.sa_flags|=SA_INTERRUPT;
#endif
}else{
#ifdefSA_RESTART
act.sa_flags|=SA_RESTART;
#endif
}
if(sigaction(signo,&act,&oact)<0)
return(SIG_ERR);
return(oact.sa_handler);
}
/*client.c*/
#include"myfunc.h"
intmain(intargc,char**argv)
{
intsockfd;
structsockaddr_inservaddr;
if(argc!
=2)
printf("usage:
tcpcli");
if((sockfd=socket(AF_INET,SOCK_STREAM,0))<0)
printf("socketerror!
");
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_port=htons(SERV_PORT);
servaddr.sin_addr.s_addr=inet_addr(argv[1]);
if(connect(sockfd,(structsockaddr*)&servaddr,sizeof(servaddr))<0)
{
printf("linkerror!
%s\n",strerror(errno));
return0;
}
charasd[5]="hello";
writen(sockfd,asd,5);
charbuf[MAXSIZE]={};
intd=0;
intfile_len=0;
intfds=open("file_in_client.txt",O_CREAT|O_RDWR|O_TRUNC,0666);
while((d=readn(sockfd,buf,MAXSIZE)))
file_len+=writen(fds,buf,d);
printf("file_len:
%d\n",file_len);
printf("Thefilehasbeenreceived!
\n");
return0;
}
/*server_1.c*/
#include"myfunc.h"
intmain(intargc,char**argv)
{
intn,m,b,listenfd,connfd;
structsockaddr_inservaddr;
if(n=(listenfd=socket(AF_INET,SOCK_STREAM,0))<0)
printf("listenerror");
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(9996);
if(m=(bind(listenfd,(structsockaddr*)&servaddr,sizeof(servaddr)))<0)
printf("binderror,%s",strerror(errno));
if((b=listen(listenfd,3))<0)
printf("blistenerror");
structsockaddr_inclientAdd;
for(;;)
{
socklen_tlen;
len=sizeof(clientAdd);
charbuf[MAXSIZE];
connfd=accept(listenfd,(structsockaddr*)&clientAdd,&len);
charqwe[5];
readn(connfd,qwe,5);
intfid=open("file_in_server.txt",O_RDWR,0666);
ints=0;
intlen1=0;
while(s=readn(fid,buf,MAXSIZE))
len1=writen(connfd,buf,s);
printf("seroneThefilehasbeensenttotheclient!
\n");
close(connfd);
}
}
/*server_2.c*/
#include"myfunc.h"
intmain(intargc,char**argv)
{
pid_tpid;
intn,m,b,listenfd,connfd;
structsockaddr_inservaddr;
voidsig_chid(int);
if(n=(listenfd=socket(AF_INET,SOCK_STREAM,0))<0)
printf("listenerror");
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(SERV_PORT);
if(m=(bind(listenfd,(structsockaddr*)&servaddr,sizeof(servaddr)))<0)
printf("binderror,%s",strerror(errno));
if((b=listen(listenfd,3))<0)
printf("listenerror");
signal(SIGCHLD,sig_chid);
structsockaddr_inclientAdd;
for(;;)
{
socklen_tlen;
len=sizeof(clientAdd);
charbuf[MAXSIZE];
ints=0;
if((connfd=accept(listenfd,(structsockaddr*)&clientAdd,&len))<0){
if(errno==EINTR)
continue;
else
printf("accepterror\n");
}
if((pid=fork())==0)
{
close(listenfd);
charqwe[5];
readn(connfd,qwe,5);
intfid=open("file_in_server.txt",O_RDWR,0666);
intlen1=0;
while(s=readn(fid,buf,MAXSIZE))
len1=writen(connfd,buf,s);
printf("sertwoThefilehasbeensenttotheclient!
\n");
close(connfd);
exit(0);
}
close(connfd);
}
}
/*server_3.c*/
#include"myfunc.h"
intmain(intargc,char**argv)
{
inti,maxfd,maxi,listenfd,connfd,sockfd;
intnready,client[FD_SETSIZE];
fd_setrset;
charbuf[MAXSIZE];
socklen_tclilen;
structsockaddr_incliaddr,servaddr;
listenfd=socket(AF_INET,SOCK_STREAM,0);
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family=AF_INET;
servaddr.sin_addr.s_addr=htonl(INADDR_ANY);
servaddr.sin_port=htons(SERV_PORT);
bind(listenfd,(structsockaddr*)&servaddr,sizeof(servaddr));
listen(listenfd,3);
maxfd=listenfd;
maxi=-1;
for(i=0;iclient[i]=-1;
FD_ZERO(&rset);
for(;;){
FD_SET(listenfd,&rset);
nready=select(maxfd+1,&rset,NULL,NULL,NULL);
if(FD_ISSET(listenfd,&rset)==1){
clilen=sizeof(cliaddr);
connfd=accept(listenfd,(structsockaddr*)&cliaddr,&clilen);
for(i=0;iif(client[i]<0){
client[i]=connfd;
break;
}
if(i==FD_SETSIZE){
printf("toomanyclients");
fflush(stdout);
}
FD_SET(connfd,&rset);
if(connfd>maxfd)
maxfd=connfd;
if(i>maxi)
maxi=i;
if(--nready<=0)
continue;
}
for(i=0;i<=maxi;i++){
if((sockfd=client[i])<0)
continue;
if(FD_ISSET(sockfd,&rset)){
charqwe[10];
readn(connfd,qwe,5);
intfid=open("file_in_server.txt",O_RDWR,0666);
ints=0;
intlen1=0;
while(s=readn(fid,buf,MAXSIZE))
len1=writen(sockfd,buf,s);
printf("Thefilehasbeensenttotheclient!
\n");
close(sockfd);
FD_CLR(sockfd,&rset);
client[i]=-1;
}
}
}
return0;
}