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

详解 QT 多线程 TCP 文件接收服务器实例(1)

2013-08-07 17:48 495 查看
本文介绍的是QT 多线程 TCP 文件接收服务器实例,如果你想深入了解这方面的资料的话,请关注本文末尾,不多说,我们先来看内容。

因为项目需要,需要跨平台编写网络传输程序。

目标:

用户端:linux(arm平台),完成文件的传输

服务器:windows ,使用多线程的文件的接收

实现无线的文件传输功能

用户端程序,用标准的socket完成文件传输的功能,代码如下:

 // Linux下网络编程,客户端程序代码    
 
 //程序运行参数:    
 // ./client IPADDRESS PORTNUMBER    
 // (其中IPADDRESS是服务端IP地址,PORTNUMBER是服务端用于监听的端口)    
 //    
   
 #include <stdio.h> 
 #include <stdlib.h> 
 #include <errno.h> 
 #include <string.h> 
 #include <netdb.h> 
 #include <ctype.h> 
 #include <unistd.h> 
#include <sys/types.h> 
 #include <sys/socket.h> 
  #include <netinet/in.h> 
#include <sys/time.h> 
 
 //用这个my_read()函数代替本来的read()函数原因有以下几点:   
//   
 //ssize_t read(int fd,void *buf,size_t nbyte)   
//read函数是负责从fd中读取内容。当读成功时,read返回实际所读的字节数;如果   
 //返回的值是0,表示已经读到文件的结束了;小于0表示出现了错误。   
 //   
 // 1)如果错误为EINTR说明read出错是由中断引起的,继续读。   
 // 2)如果是ECONNREST表示网络连接出了问题,停止读取。   
 
 size_t min(size_t a,size_t b)  
{  
 return( (a<b) ? a : b);  
 }  
   
 ssize_t my_write(int fd,void *buffer,size_t length)  
{  
 size_t bytes_left; //尚未写的文件大小   
 size_t writesize = 4* 1024;  
 ssize_t written_bytes; //已经写的文件大小   
 char *ptr;  
 ptr=buffer;  
bytes_left=length;  
  while(bytes_left>0)  
 {  
 //开始写   
 written_bytes=write(fd,ptr,min(bytes_left,writesize));  
 //出现了写错误   
if(written_bytes<=0)  
 {  
 //中断错误,置零重新写   
if(errno==EINTR)  
written_bytes=0;  
 //其他错误,退出不写了   
 else   
 return(-1);  
}  
 //从剩下的地方继续写   
bytes_left-=written_bytes;  
 ptr+=written_bytes;  
 }  
return(0);  
}  
 
: int main(int argc, char *argv[])  
{  
 int sockfd; //通信套接字描述符   
char *buffer; //缓冲区   
struct sockaddr_in server_addr; //服务器地址结构   
 struct hostent *host; //主机地址与名称信息结构   
 int nbytes; //端口号、字节数   
 FILE *fp; //文件指针   
int nfilesize; //文件大小   
 char str[128]; //文件名   
 char yes='Y'; //流程控制   
 struct timeval tpstart,tpend; //用于记录文件传输时间   
 float timeuse; //文件传输所用时间   
char *hostname="127.0.0.1";//主机名/ip地址   
 int portnumber=4321;//端口号   
   
 //提示用户输入完整的命令行参数   
 if(argc!=3)  
 {  
 fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[0]);  
 printf("using defaults:\nhostname: %s\nportnumber: %d\n",hostname,portnumber);  
 }  
 
 //如果利用用户输入的域名无法获得正确的主机地址信息,则退出   
 if (argc>1)  
 {  
 if((host=gethostbyname(argv[1]))==NULL)  
{  
 fprintf(stderr,"Gethostname error\n");  
exit(1);  
 }  
 }  
 
else   
 if((host=gethostbyname(hostname))==NULL)  
 {  
fprintf(stderr,"Gethostname error\n");  
 exit(1);  
}   
if(argc>2)  
 //如果用户输入的端口不正确,则提示并退出   
 if((portnumber=atoi(argv[2]))<0)  
{  
fprintf(stderr,"Usage:%s hostname portnumber\a\n",argv[0]);  
 exit(1);  
}  
//客户程序开始建立 sockfd描述符,创建通信套接字   
 if((sockfd=socket(AF_INET,SOCK_STREAM,6))==-1)  
{  
 fprintf(stderr,"Socket Error:%s\a\n",strerror(errno));  
exit(1);  
 }  
//客户程序填充服务端的地址信息   
 bzero(&server_addr,sizeof(server_addr));  
 server_addr.sin_family=AF_INET;  
 server_addr.sin_port=htons(portnumber);  
 server_addr.sin_addr=*((struct in_addr *)host->h_addr);   
//客户程序发起连接请求    
if(connect(sockfd,(struct sockaddr *)(&server_addr),sizeof(struct sockaddr))==-1)  
 {  
 fprintf(stderr,"Connect Error:%s\a\n",strerror(errno));  
 exit(1);  
}  
 printf("Connection Succeed!\n");  
 while (toupper(yes)=='Y')  
 {  
 //提示用户输入文件路径   
 printf("Please input the file location:");  
 scanf("%s",str);  
 while ((fp=fopen(str,"r"))==NULL)  
{  
 fprintf(stderr,"File open error,Retry!\n");  
 printf("Please input the file location:");  
 scanf("%s",str);  
 //exit(1);   
 }  
  getchar();  
   
 //获取打开的文件的大小,并将文件整个读入内存中   
 fseek(fp,0L,SEEK_END);  
 nfilesize=ftell(fp);  
 rewind(fp);//most important!!!!!   
 char *p=(char *)malloc(nfilesize);  
if (fread((void *)p,nfilesize,1,fp)<1) {  
if (feof(fp))  
printf("read end of file!\nquit!\n");  
else   
 printf("read file error!\n");  
 }  
 //将要传输的文件的大小信息发送给客户端   
 if (my_write(sockfd,(void *)&nfilesize,4)==-1)  
{  
 fprintf(stderr,"Write Error:%s\n",strerror(errno));  
exit(1);  
}  
 printf("Begin to transfer the file!\n");  
getchar();  
 
//获取传输初始时间   
gettimeofday(&tpstart,NULL);  
 
 //传输文件   
if (my_write(sockfd,p,nfilesize)==-1)  
  {  
fprintf(stderr,"Transfer failed!");  
 exit(1);  
 }  
 //获取传输结束时间   
 gettimeofday(&tpend,NULL);  
//计算整个传输用时   
timeuse=1000000*(tpend.tv_sec-tpstart.tv_sec)+(tpend.tv_usec-tpstart.tv_usec);  
timeuse/=1000000;   
 printf("Transfer Succeed!\nFile Name: %s\nFile Size: %d bytes\nTotal Time: 
%f seconds\nTransfer Speed: %f bytes/second",str,nfilesize,timeuse,((float)nfilesize)/timeuse);  
 free(p); //释放文件内存   
 fclose(fp); //关闭文件   
 // printf("\nTransfer another file?(Y/N): ");   
 //scanf("%c",&yes);   
// getchar();   
 yes='n';  
 }  
 //结束通讯,关闭套接字,关闭连接   
 close(sockfd);  
 printf("\nClient Exit!~~\n");  
 exit(0);  
 } 

服务器端代码列表:





具体代码如下:

“tcpserver.h”  
#ifndef TCPSERVER_H  
 #define TCPSERVER_H   
 #include <QTcpServer> 
 //继承自QTcpServer,完成TCPSEVER的建立的类   
 class TcpServer : public QTcpServer  
{  
Q_OBJECT  
 public:  
 explicit TcpServer(QObject *parent = 0);  
  //此信号用来更新UI   
 signals:  
void bytesArrived(qint64,qint32,int);  
//QTcpServer类自带的函数,详情参考Class Reference   
protected:  
 void incomingConnection(int socketDescriptor);  
};  
 #endif // TCPSERVER_H  

TCPSERVER继承QTcpServer,主要完成TCP服务器的建立,类中最主要的成员函数为虚函数incomingConnection(int socketDescriptor)的定义。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: