详解 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)的定义。
因为项目需要,需要跨平台编写网络传输程序。
目标:
用户端: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)的定义。
相关文章推荐
- 详解 QT 多线程 TCP 文件接收服务器实例(2)
- QT编写多线程TCP文件接收服务器
- QT编写多线程TCP文件接收服务器
- QT编写多线程TCP文件接收服务器
- QT编写多线程TCP文件接收服务器
- QT编写多线程TCP文件接收服务器
- Qt5 基于TCP传输的发送/接收文件服务器(支持多客户端)
- Qt5 基于TCP传输的发送/接收文件服务器(支持多客户端)
- Qt5 基于TCP传输的发送/接收文件服务器(支持多客户端)
- Qt5 基于TCP传输的发送/接收文件服务器(支持多客户端)
- java 网络流 TCP Socket和SeverSocket 上传文件(字节流)+ 服务器多线程
- linux tcp多线程服务器与客户端编程实例
- Java编程实现多线程TCP服务器完整实例
- TCP并发服务器实例--多线程
- Nginx服务器配置文件nginx.conf实例详解
- Android 上传文件到服务器实例详解
- 服务器端接收来自多个客户端的文件,服务器要求用多线程
- Android 上传文件到服务器实例详解
- linux下搭建能同时接收UDP和TCP连接的socket并发多线程服务器
- Qt5--学习笔记-TCPsocket文件发送、接收