C/C++14天气APP:文件传输系统(tcpput/getfile.cpp客户端,tcpfileserver.cpp)
Posted 码农编程录
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++14天气APP:文件传输系统(tcpput/getfile.cpp客户端,tcpfileserver.cpp)相关的知识,希望对你有一定的参考价值。
1.TCP粘包/超时:全双工,拆粘包
ftp协议进行文件传输性能不够【FTP协议是TCP/IP协议的一部分,严格说是应用层协议,TCP通信两大瓶颈:带宽
,交互次数过多(获取对方服务器时间,文件列表,改名等)
】。windows平台ftp安装服务端麻烦,不同ftp服务器在使用时略有区别,兼容性不好【比如ftp.list里*号圆点都可以,有的不行】。系统内部不用ftp,外部用ftp
(因为不能把自己程序部署到别人服务器上,别人服务器上也只能装个ftp服务端)。
如下比如B站作者将视频文件发到视频上传服务器
进行审核,审核完后通过文件传输系统发给视频播放服务器
【一个播放服务器是不可能响应那么多播放请求的,肯定是服务器集群】。
为什么要传文件
而不是tcp报文
(有些数据就是文件方式组织的,比如视频),因为传文件更快。如下拆包和粘包:
如下解决粘包拆包:头/定长/分隔符。
如下是第一种方法,粘包还是会出现,但可以区分开。
如下是第三种方法,自定义分隔符。
如下在_public.h客户端。
如下在_public.h服务端,InitServer函数中没指定ip,说明哪任何ip都能连。
如下是_public.h定义的几个方法,TcpRead方法最后调用recv函数,recv会阻塞一直等待,实际开发不会等,加上一个超时机制
:比如一分钟还没给我发信息的话,我会断开你释放资源进程退出。Readn
和Writen
是对recv和send扩展。
如下在_public.h定义解决粘包问题,自定义TCP报文格式。
select不是sql语句是系统调用
。select(非阻塞)原本用于I/O复用,现用于超时机制。客户端连上来后启动一个进程消耗资源,所以服务端在客户端某原因断开时主动将客户端进程退出释放资源。
如下CTcpClient::Read()没用超时机制(超时不管在客户端还是服务端都用得着)。
// 本程序演示采用CTcpClient类,实现socket通讯的客户端,demo11.cpp
#include "_public.h"
int main(int argc,char *argv[])
if (argc != 3)
printf("\\n");
printf("Using:./demo11 ip port\\n\\n");
printf("Example:./demo11 118.89.50.198 5010\\n\\n");
printf("本程序演示采用CTcpClient类,实现socket通讯的客户端。\\n\\n");
return -1;
CTcpClient TcpClient;
//111111111111111111111111111111111111111111111111111111111.向服务器发起连接
if (TcpClient.ConnectToServer(argv[1],atoi(argv[2])) == false)
printf("TcpClient.ConnectToServer(%s,%d) failed.\\n",argv[1],atoi(argv[2])); return -1;
char strRecvBuffer[1024],strSendBuffer[1024];
memset(strSendBuffer,0,sizeof(strSendBuffer));
strcpy(strSendBuffer,\\
"英超最后一轮,卡里克踢完了在曼联的最后一场正式比赛,这意味着红魔上次称霸欧冠的黄金一代全部退场。");
//11111111111111111111111111111111111111111111111111112.把strSendBuffer内容发送给服务端
if (TcpClient.Write(strSendBuffer)==false)
printf("TcpClient.Write() failed.\\n"); return -1;
printf("send ok:%s\\n",strSendBuffer);
memset(strRecvBuffer,0,sizeof(strRecvBuffer));
//1111111111111111111111111111111111111111111111111113.接收服务端返回的报文(下面Read没有超时机制)
if (TcpClient.Read(strRecvBuffer)==false)
if (TcpClient.m_btimeout==true) printf("timeout\\n");
printf("TcpClient.Read() failed.\\n"); return -1;
printf("recv ok:%s\\n",strRecvBuffer);
return 0;
// 本程序演示采用CTcpServer类,实现socket通讯的服务端,demo12.cpp
#include "_public.h"
int main(int argc,char *argv[])
if (argc != 2)
printf("\\n");
printf("Using:./demo12 port\\n\\n");
printf("Example:./demo12 5010\\n\\n");
printf("本程序演示采用CTcpServer类,实现socket通讯的服务端。\\n\\n");
return -1;
CTcpServer TcpServer;
//1111111111111111111111111111111111111111111111111111.服务端初始化
if (TcpServer.InitServer(atoi(argv[1])) == FALSE)
printf("TcpServer.InitServer(%s) failed.\\n",argv[1]); return -1;
//1111111111111111111111111111111111111111111111111112.等待客户端的连接
if (TcpServer.Accept() == FALSE)
printf("TcpServer.Accept() failed.\\n"); return -1;
char strRecvBuffer[1024],strSendBuffer[1024];
memset(strRecvBuffer,0,sizeof(strRecvBuffer));
//111111111111111111111111111111111111111111111111113.读取客户端的报文,等时间是20秒,有超时机制
if (TcpServer.Read(strRecvBuffer,20)==FALSE)
printf("TcpServer.Read() failed.\\n"); return -1;
printf("recv ok:%s\\n",strRecvBuffer);
memset(strSendBuffer,0,sizeof(strSendBuffer));
strcpy(strSendBuffer,"ok");
//111111111111111111111111111111111111111111111111114.向客户端返回响应内容
if (TcpServer.Write(strSendBuffer)==FALSE)
printf("TcpServer.Write() failed.\\n"); return -1;
printf("send ok:%s\\n",strSendBuffer);
return 0;
下面添加睡眠
即改为超时机制。
下面利用m_btimeout成员(超时为true)打印出是否超时。
服务端分不清客户端是网络原因还是程序自身出问题断开,只知道TCP通道异常。
下面是GetIP()。
2.简单文件传输:CTcpClient,CTcpServer
// 本程序演示采用CTcpClient类,实现socket通讯的客户端和文件传输,demo13.cpp
#include "_public.h"
bool SendFile(int sockfd,char *filename,int filesize); //把文件的内容发送给服务端
int main(int argc,char *argv[])
if (argc != 4)
printf("\\n");
printf("Using:./demo13 ip port filename\\n\\n");
printf("Example:./demo13 118.89.50.198 5010 test1.jpg\\n\\n");
printf("本程序演示采用CTcpClient类,实现socket通讯的客户端和文件传输。\\n\\n");
return -1;
if (access(argv[3],R_OK) != 0) //判断文件是否存
printf("file %s not exist.\\n",argv[3]); return -1;
int uFileSize=0;
char strMTime[20],strRecvBuffer[1024],strSendBuffer[1024];
memset(strMTime,0,sizeof(strMTime)); //获取文件的时间和大小
FileMTime(argv[3],strMTime);
uFileSize=FileSize(argv[3]); //获取文件的大小
// 把文件的信息封装成一个xml报文,发送给服务端
memset(strSendBuffer,0,sizeof(strSendBuffer));
snprintf(strSendBuffer,100,"<filename>%s</filename><mtime>%s</mtime><size>%lu</size>",argv[3],strMTime,uFileSize);
CTcpClient TcpClient;
//1111111111111111111111111111111111111111111111111111.向服务器发起连接
if (TcpClient.ConnectToServer(argv[1],atoi(argv[2])) == false)
printf("TcpClient.ConnectToServer(%s,%d) failed.\\n",argv[1],atoi(argv[2])); return -1;
//1111111111111111111111111111111111111111112.把文件信息的xml发送给服务端,并没有接收服务端回应,没必要,减少tcp交互次数
if (TcpClient.Write(strSendBuffer)==false)
printf("TcpClient.Write() failed.\\n"); return -1;
printf("send xml:%s\\n",strSendBuffer);
printf("send file ...");
//111111111111111111111111111111111111111111111111111113.把文件的内容发送给服务端
if (SendFile(TcpClient.m_sockfd,argv[3],uFileSize)==false)
printf("SendFile(%s) failed.\\n",argv[3]); return -1;
memset(strRecvBuffer,0,sizeof(strRecvBuffer));
//1111111111111111111111111111111111111111111111111114.接收服务端返回的回应报文
if (TcpClient.Read(strRecvBuffer)==false)
printf("TcpClient.Read() failed.\\n"); return -1;
if (strcmp(strRecvBuffer,"ok")==0)
printf("ok.\\n");
else
printf("failed.\\n");
return 0;
//111111111111111111111111111111111111111111111111113.把文件的内容发送给服务端
bool SendFile(int sockfd,char *filename,int filesize)
int bytes=0;
int total_bytes=0;
int onread=0;
char buffer[1000];
FILE *fp=NULL;
if ( (fp=fopen(filename,"rb")) == NULL )
printf("fopen(%s) failed.\\n",filename); return false;
while (true)
memset(buffer,0,sizeof(buffer));
if ((filesize-total_bytes) > 1000) onread=1000; //一次读1000个字节
else onread=filesize-total_bytes;
bytes=fread(buffer,1,onread,fp);
if (bytes > 0)
if (Writen(sockfd,buffer,bytes) == false)
printf("Writen() failed.\\n"); fclose(fp); fp=NULL; return false;
total_bytes = total_bytes + bytes;
if ((int)total_bytes == filesize) break;
fclose(fp);
return true;
// 本程序演示采用CTcpServer类,实现socket通讯的服务端和文件传输,demo14.cpp
#include "_public.h"
bool RecvFile(char *strRecvBuffer,int sockfd,char *strfilename); //接收文件的内容
int main(int argc,char *argv[])
if (argc != 3)
printf("\\n");
printf("Using:./demo14 port filename\\n\\n");
printf("Example:./demo14 5010 test2.jpg\\n\\n"); //test2.jpg重新命名
printf("本程序演示采用CTcpServer类,实现socket通讯的服务端和文件传输。\\n\\n");
return -1;
CTcpServer TcpServer;
//1111111111111111111111111111111111111111111111111111.服务端初始化
if (TcpServer.InitServer(atoi(argv[1])) == false)
printf("TcpServer.InitServer(%s) failed.\\n",argv[1]); return -1;
//1111111111111111111111111111111111111111111111111112.等待客户端的连接
if (TcpServer.Accept() == false)
printf("TcpServer.Accept() failed.\\n"); return -1;
//11111111111111111111111111111111111111111113.读取客户端的报文,等时间是20秒
char strRecvBuffer[1024],strSendBuffer[1024];
memset(strRecvBuffer,0,sizeof(strRecvBuffer));
if (TcpServer.Read(strRecvBuffer,20)==false)
printf("TcpServer.Read() failed.\\n"); return -1;
printf("recv:%s\\n",strRecvBuffer);
printf("recv file ...");
//111111111111111111111111111111111111111111114.接收文件的内容
memset(strSendBuffer,0,sizeof(strSendBuffer));
if (RecvFile(strRecvBuffer,TcpServer.m_connfd,argv[2])==true)
strcpy(strSendBuffer,"ok");
printf("ok.\\n");
else
strcpy(strSendBuffer,"failed");
printf("failed.\\n");
//1111111111111111111111111111111111111111111111111115.接收ok后,向客户端返回响应内容
if (TcpServer.Write(strSendBuffer)==false)
printf("TcpServer.Write() failed.\\n"); return -1;
printf("send:%s\\n",strSendBuffer);
return 0;
//1111111111111111111111111111111111111111111111111114.接收文件的内容
bool RecvFile(char *strRecvBuffer,int sockfd,char *strfilename)
int ufilesize=0;
char strmtime[20];
memset(strmtime,0,sizeof(strmtime));
// 获取待接收的文件的时间和大小
GetXMLBuffer(strRecvBuffer,"mtime",strmtime);
GetXMLBuffer(strRecvBuffer,"size",&ufilesize);
FILE *fp=NULL;
if ( (fp=fopen(strfilename,"wb")) ==NULL)
printf("create %s failed.\\n",strfilename); return false;
int total_bytes=0;
int onread=0;
char buffer[1000];
while (true)
memset(buffer,0,sizeof(buffer));
if ((ufilesize-total_bytes) > 1000) onread=1000; //根据文件大小知道文件接下来读取多少内容
else onread=ufilesize-total_bytes;
if (Readn(sockfd,buffer,onread) == false)
printf("Readn() failed.\\n"); fclose(fp); fp=NULL; return false;
fwrite(bu以上是关于C/C++14天气APP:文件传输系统(tcpput/getfile.cpp客户端,tcpfileserver.cpp)的主要内容,如果未能解决你的问题,请参考以下文章
C/C++9天气APP:Oracle的虚表/日期/序列,索引/视图/链路/同义词,数据库高可用性
C/C++8天气APP:Oracle数据库安装,表操作,C语言操作Oracle数据库
C/C++10天气APP:MySQL,PostgreSQL,环境变量,动静态库,Linux/Oracle字符集
C/C++7天气APP:生成观测数据txt/xml文件(crtsurfdata.cpp),ftp协议及ftp采集模块(_ftp.h,_ftp.cpp,ftpgetfiles.cpp)
C/C++13天气APP:数据挖掘/HTTP协议/非结构化数据存储(filetoblob.cpp),数据管理/监控告警(hsmtable.cpp,tbspaceinfo.cpp)