时间:大学的项目
项目功能:文件的上传、下载、秒传、断点续传,其他基本指令
项目描述
1.使用tcp可靠传输协议通过三次握手进行客户端和服务器端的连接和文件的传输
2.采用多线程编程实现多客户端的请求连接
3.客户端发送请求数据包,服务器端进行数据包的解析,并响应请求,以实现文件的上传、下载和其他指令
4.通过存储文件的MD5值,实现秒传和断点续传
c/s模型(客户端服务器端模型)
服务器端
(1)创建套接字socket
serfd=socket(AF_INET,SOCK_STREAM,0);
地址域 流式套接字 参数
(2)绑定地址和端口信息bind
struct sockaddr_in saddr;
sin.saddr_family=AF_INET;
sin.saddr_port=htons(SER_PORT);
sin.saddr_addr.s_addr=SER_IP;
bind(serfd,(struct sockaddr*)&saddr,sizeof(saddr));
创建成功的文件描述符 地址信息 地址信息长度
(3)监听套接字listen
listen(serfd,n);
套接字的文件描述符 监听队列的大小
同一时间接受客户链接请求的个数
不能超过1024个
(4)接受链接请求accept
int confd=accept(serfd,(struct socksaddr*)&sadddr,sizeof(saddr));
(5)通信send/recv
char buff[1024];
memset(buff,0,sizeof(buff));
recv(confd,buff,sizeof(buff),0);
memmset(buff,0,sizeof(buff));
gets(buff);
send(confd,buff,sizeof(buff),0);
(6)关闭通信close
close(serfd);
客户端
(1)
(2)int sockfd=socket(AF_INET,SOCK_STREAM,0);
assert(sockfd!=-1);
struct sockaddr_in saddr;
memset(&saddr,0,sizeof(saddr));
saddr.sin_family=AF_INET;
saddr.sin_port=htons(SER_PORT);
saddr.sin_addr.s_addr=inet_addr(SER_IP);
int res=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//客户端主动发起连接
assert(res!=-1);
改进:
1.
(用
sendfile
发送数据)
sendfile
在两个文件描述符之间直接传输数据(完全在内核中操作),从而
避免了内核缓冲区和用户缓冲区之间拷贝数据
,效率很高,这被称为零拷贝.
2.
加入线程池。
线程池避免大量线程开辟带来的系统资源的浪费,他提前创建很多任务线程,等待处理时间就行。
项目中遇到的问题;
黏包问题;
黏包原因
:字节流:(1)应用程序对数据的
发送和接收是没有边界限制
的
(2)
要发送的数据小于TCP发送缓冲区的大小,TCP
将多次写入缓冲区的数据一次发送出去
,将会发生粘包
(3)
接收数据端的应用层
没有及时读取接收缓冲区中的数据
,将发生粘包。
解决
:
(1)
发送端
给每个数据包添加包首部
,首部中应该至少包含数据包的长度3,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。
(2)
发送端
将每个数据包封装为固定长度
(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
(3)可以
在数据包之间设置边界
,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。
等等
。
在此项目中,黏包的解决是:不能连续两次发送,两次中间应该recv一次
当上传完成后,通过比较两个文件的MD5值来判断文件的一致性
1、通过 md5sum * > serfile.log 把服务端所有文件的MD5值和文件名导入到serfile中
2、客户端同理,生成clifile.log文件
3、通过自己是实现的测试代码匹配两个文件中同名文件的MD5值是否相同,
具体过程如下:
1、通过open()打开serfile.log和clifile.log
2、分别读取每一个文件中的数据导入到自定义的结构体vector中,结构体为{MD5,name}
3、比较两个vector中name是否相同,相同再比较MD5值,并把这条记录保存在result.log文件中
4、程序运行结束后,通过查询result.log文件即可获得文件传输过程中文件的一致性情况
.log文件是日志文件,
通常是系统或者某些软件对已完成的某种处理的记录,以便将来做为参考,它并没有固定的格式,通常是文本文件,可以用记事本打开以查看内容,当然很可能是其它格式,直接打开就是乱码。大部分的log可以从文件名看出它的作用,比如uninstall.log或是error.log,当然前者通常是软件安装过程中生成的记录,以便将来卸载的时候可以提供给卸载程序使用,后者通常是用来记录一些软件运行中的错误信息等等。
项目中遇到的问题: 在文件传输时如果出现客户端突然关闭,服
务器也会关闭。通过调试和查阅资料发现是因为客户端在关闭时,
如果服务器继续向客户端发送数据(send)会导致服务器收到信号
而结束进程。于是引入非阻塞模式的文件描述符及 I/O 复用技术,
在每次发送数据前首先 recv 一次,通过判断 recv 的结果采取
的措施,解决了这个问题。