您的位置:首页 > 理论基础 > 计算机网络

Socket网络程序设计(3) ———— 利用tcp完成文件传输的设计和实现

2017-08-10 09:55 501 查看

用TCP/TP进行网际互连(3)

———— 利用tcp完成文件传输的设计和实现

1、要求介绍

利用循环面向连接的模型完成固定文件的传输

由固定文件扩展成手动输入或选择文件

——废话少说,直接上代码——

2、实现代码

服务器:

(1.初始化服务器端的socket:)
int sockfd,connfd;
struct sockaddr_in svraddr,clientaddr;
bzero(&svraddr,sizeof(svraddr));

svraddr.sin_family=AF_INET;
svraddr.sin_addr.s_addr=htonl(INADDR_ANY);
svraddr.sin_port=htons(PORT);

sockfd=socket(AF_INET,SOCK_STREAM,0);

(2.进行绑定:)
if(bind(sockfd,(struct sockaddr*)&svraddr,sizeof(svraddr))<0)
{
perror("bind");
exit(1);
}
(3.变为被动模式,进行监听)
//listen
if(listen(sockfd,LISTENQ)<0)
{
perror("listen");
exit(1);
}
(4.循环等待实现文件的传输)
while(1)
{
socklen_t length=sizeof(clientaddr);

//accept
connfd=accept(sockfd,(struct sockaddr*)&clientaddr,&length);
if(connfd<0)
{
perror("connect");
exit(1);
}

//send file imformation
char buff[BUFFSIZE];
int count;
bzero(buff,BUFFSIZE);
strncpy(buff,filename,strlen(filename)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(filename));
count=send(connfd,buff,BUFFSIZE,0);
if(count<0)
{
perror("Send file information");
exit(1);
}

//read file
FILE *fd=fopen(filename,"rb");
if(fd==NULL)
{
printf("File :%s not found!\n",filename);
}
else
{
bzero(buff,BUFFSIZE);
int file_block_length=0;
while((file_block_length=fread(buff,sizeof(char),BUFFSIZE,fd))>0)
{
printf("file_block_length:%d\n",file_block_length);
if(send(connfd,buff,file_block_length,0)<0)
{
perror("Send");
exit(1);
}
bzero(buff,BUFFSIZE);
}
fclose(fd);
printf("Transfer file finished !\n");
}
close(connfd);
}


客户端

主函数:
int main(int argc, char **argv[])
{
int clientfd;
//连接
clientfd=connectTCP("127.0.0.1",PORT);
//接收信息
recvTCP(clientfd);
//关闭
close(clientfd);
return 0;
}
(可以看出整个主函数变得非常简洁)

//connectTCP函数封装了TCP的连接过程
int connectTCP(const char *host, const char *port){
int clientfd;
struct sockaddr_in clientaddr;
bzero(&clientaddr,sizeof(clientaddr));

clientaddr.sin_family=AF_INET;
clientaddr.sin_addr.s_addr=htons(INADDR_ANY);
clientaddr.sin_port=htons(0);

clientfd=socket(AF_INET,SOCK_STREAM,0);

if(clientfd<0)
{
perror("socket");
exit(1);
}

if(bind(clientfd,(struct sockaddr*)&clientaddr,sizeof(clientaddr))<0)
{
perror("bind");
exit(1);
}

struct sockaddr_in svraddr;
bzero(&svraddr,sizeof(svraddr));
if(inet_aton(host,&svraddr.sin_addr)==0)
{
perror("inet_aton");
exit(1);
}
svraddr.sin_family=AF_INET;
svraddr.sin_port=htons(port);

socklen_t svraddrlen=sizeof(svraddr);
if(connect(clientfd,(struct sockaddr*)&svraddr,svraddrlen)<0)
{
perror("connect");
exit(1);
}
return clientfd;
}

//recvTCP封装了接收文件的过程
void recvTCP(int clientfd){
//recv file imformation
char buff[BUFFSIZE];
char filename[FILE_NAME_MAX_SIZE];
int count;
bzero(buff,BUFFSIZE);

count=recv(clientfd,buff,BUFFSIZE,0);
if(count<0)
{
perror("recv");
exit(1);
}
strncpy(filename,buff,strlen(buff)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buff));

printf("Preparing recv file : %s  \n",filename);

//recv file
FILE *fd=fopen(filename,"wb+");
if(NULL==fd)
{
perror("open");
exit(1);
}
bzero(buff,BUFFSIZE);

int length=0;
while(length=recv(clientfd,buff,BUFFSIZE,0))
{
if(length<0)
{
perror("recv");
exit(1);
}
int writelen=fwrite(buff,sizeof(char),length,fd);
if(writelen<length)
{
perror("write");
exit(1);
}
bzero(buff,BUFFSIZE);
}
printf("Receieved file:%s  finished!\n",filename);
fclose(fd);
}


3、代码分析

首先在服务器端利用循环面向连接的模型进行文件的传输,实现向每一个接入的客户端发送文件的服务。文件名可以手动输入来选择文件。

客户端程序进行相应的socket连接。进行封装之后,简化了主函数,使主函数变得简洁清晰了很多,通过调用connectTCP进行socket函数连接的封装,方便之后的扩展,如添加一个基于UDP协议的传输服务。

4、运行效果

服务器端启动,选择要传输的文件:



客户端连接:



测试,当传输稍大文件时:



附上我的测试成功的实验代码:

https://github.com/KevinBetterQ/Network-programming/tree/master/TCP_file
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐