基于Qt編寫的文件傳輸工具
文件傳輸工具
通過(guò)發(fā)送udp廣播消息將IP廣播給其他開(kāi)啟該程序的局域網(wǎng)機(jī)器
收到的廣播消息可以顯示在IP地址列表中,點(diǎn)擊IP地址可以自動(dòng)填充到IP地址欄內(nèi)
選擇文件后點(diǎn)擊發(fā)送可以發(fā)送給指定IP,并能在傳輸過(guò)程中顯示進(jìn)度
默認(rèn)端口6001。目前不支持修改,修改端口會(huì)導(dǎo)致網(wǎng)絡(luò)連接失敗。
界面比較簡(jiǎn)潔:

部分代碼如下:
udp發(fā)送廣播消息
void Client::SendUDPMsg() {
int ret = 0;
// 設(shè)置廣播地址
struct sockaddr_in client;
memset(&client, 0, sizeof(client));
client.sin_family = AF_INET;
client.sin_port = htons(g_udpServerPort);
client.sin_addr.s_addr = inet_addr("255.255.255.255");
int len = sizeof(SOCKADDR);
hostent* host = gethostbyname(g_serverHost.toStdString().c_str());
QString msg = QString("broadcast|%1").arg(host->h_name);
ret = sendto(m_udpClientSocket, msg.toStdString().c_str(), msg.length(), 0, (SOCKADDR*)&client, len);
}
udp接收消息:
void Client::RecvUDPMsg() {
int ret = 0;
struct sockaddr_in client;
memset(&client, 0, sizeof(client));
int len = sizeof(SOCKADDR);
char buff[BUFF_SIZE] = {0};
ret = recvfrom(m_udpServerSocket, buff, BUFF_SIZE, 0, (SOCKADDR*)&client, &len);
QString host(inet_ntoa(client.sin_addr));
if (m_localIPv4List.indexOf(host) == -1 && m_knownHosts.indexOf(host) == -1) {
qDebug() << __FUNCTION__ << "new host:" << host;
m_knownHosts.push_back(host);
(static_cast<Work*>(m_pParent))->NewHost(host);
} else {
return;
}
}
啟動(dòng)udp服務(wù):
bool Client::StartUdpServer(NetworkParams& params) {
QString host = params.serverIP;
m_hostnm = gethostbyname(host.toStdString().c_str());
if (m_hostnm != (struct hostent*)0) {
qDebug() << __FUNCTION__ << "hostname:" << m_hostnm->h_addrtype << " addr:" << m_hostnm->h_name;
}
int ret = 0;
if ((m_udpServerSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
return false;
}
int port = params.serverPort;
memset(&m_sockAddr, 0, sizeof(m_sockAddr));
m_sockAddr.sin_family = AF_INET;
m_sockAddr.sin_port = htons(port);
//m_sockAddr.sin_addr.S_un.S_addr= inet_addr(host.toStdString().c_str());
m_sockAddr.sin_addr.s_addr = INADDR_ANY;
ret = bind(m_udpServerSocket, (const struct sockaddr*)&m_sockAddr, sizeof(m_sockAddr));
if (ret < 0) {
return false;
} else {
}
GetIPv4List();
return true;
}
啟動(dòng)tcp服務(wù)用于接收文件和發(fā)送文件:
bool Client::StartTcpServer(NetworkParams& params) {
if (!m_bSocketClosed) {
return true;
}
QString host = params.serverIP;
m_hostnm = gethostbyname(host.toStdString().c_str());
if (m_hostnm != (struct hostent*)0) {
qDebug() << __FUNCTION__ << "hostname:" << m_hostnm->h_addrtype << " addr:" << m_hostnm->h_name;
}
int ret = 0;
if ((m_tcpServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
return false;
}
int port = params.serverPort;
memset(&m_sockAddr, 0, sizeof(struct sockaddr_in));
m_sockAddr.sin_family = AF_INET;
m_sockAddr.sin_addr.s_addr = INADDR_ANY;
m_sockAddr.sin_port = htons(port);
ret = bind(m_tcpServerSocket, (const struct sockaddr*)&m_sockAddr, sizeof(m_sockAddr));
if (ret < 0) {
return false;
} else {
qDebug() << __FUNCTION__ << "bind success port:" << port;
}
if (listen(m_tcpServerSocket, 512)) {
return false;
}
return true;
}
通過(guò)tcp發(fā)送文件:
bool Client::SendFile(QString strFullFilePath, QString strUserName) {
if (strFullFilePath.isEmpty() || strUserName.isEmpty()) {
return false;
}
strFullFilePath = strFullFilePath.replace("\\", "/");
QString fileName = strFullFilePath.mid(strFullFilePath.lastIndexOf("/") + 1);
QFile f(strFullFilePath);
if (!f.exists()) {
return false;
}
if (!f.open(QIODevice::ReadOnly)) {
return false;
}
f.seek(SEEK_SET);
quint64 fileSize = f.size();
char chBuff[BUFF_SIZE] = {0};
memset(chBuff, 0, BUFF_SIZE);
QString s = QString("upload|%1|%2|%3|donotremove").arg(fileName).arg(fileSize).arg(strUserName);
strcpy(chBuff, s.toStdString().c_str());
send(m_iClientSocket, chBuff, strlen(chBuff) + 1, 0);
quint64 sendSize = 0;
NetworkParams params;
params.totalSize = fileSize;
while (sendSize < fileSize) {
memset(chBuff, 0, BUFF_SIZE);
qint64 iRead = f.read(chBuff, BUFF_SIZE);
if (iRead < 0) {
f.close();
return false;
}
int iSend = send(m_iClientSocket, chBuff, iRead, 0);
if (iSend < 0) {
f.close();
return false;
}
int temp = iRead;
while (iSend < temp) {
iSend = send(m_iClientSocket, chBuff + iSend, temp - iSend, 0);
if (iSend < 0) {
f.close();
return false;
}
temp = temp - iSend;
}
sendSize += iSend;
f.seek(sendSize);
params.recved = sendSize;
(static_cast<Work*>(m_pParent))->UpdateProgress(params);
}
f.close();
closesocket(m_iClientSocket);
m_bSocketClosed = true;
}
通過(guò)tcp接收文件:
bool Client::RecvFile() {
SOCKET clientSock = NULL;
struct sockaddr in_addr = {0};
int addrLen = sizeof(in_addr);
clientSock = accept(m_tcpServerSocket, (struct sockaddr*)&in_addr, &addrLen);
if (clientSock == SOCKET_ERROR) {
return false;
}
ssize_t len = 0;
char buff[BUFF_SIZE] = {0};
len = recv(clientSock, buff, sizeof(buff), 0);//1. get filename and client ip
if (len <= 0) {
return false;
}
QString fileNameAndClientIP(buff);//upload|filename|filesize|hostname
QStringList sl = fileNameAndClientIP.split("|");
if (sl.length() < 3) {
return false;
}
QString fullFilePath = APPLICATION_DIR + "/" + sl.at(3);
QDir d(fullFilePath);
if (!d.exists()) {
if (!d.mkdir(fullFilePath)) {
((Work*)m_pParent)->WarnMsg(QString("創(chuàng)建目錄[%1]失敗").arg(fullFilePath));
return false;
}
}
qlonglong fileSize = sl.at(2).toLongLong();
QString fullName = fullFilePath + "/" + sl.at(1);
QFile f(fullName);
if (!f.open(QFile::ReadWrite)) {
((Work*)m_pParent)->WarnMsg(QString("打開(kāi)文件:%1失敗").arg(fullName));
return false;
}
qlonglong recvLen = 0;
NetworkParams params;
params.totalSize = fileSize;
while (recvLen < fileSize) {
memset(buff, 0, sizeof(buff));
len = recv(clientSock, buff, sizeof(buff), 0);
if (len <= 0) {
break;
}
recvLen += len;
f.write(buff, len);
params.recved = recvLen;
(static_cast<Work*>(m_pParent))->UpdateProgress(params);
}
f.close();
closesocket(clientSock);
(static_cast<Work*>(m_pParent))->ReceivedFile(fullName);
}
以上就是基于Qt編寫的文件傳輸工具的詳細(xì)內(nèi)容,更多關(guān)于Qt編寫文件傳輸?shù)馁Y料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之單向鏈表詳解分析
鏈表可以說(shuō)是一種最為基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)了,而單向鏈表更是基礎(chǔ)中的基礎(chǔ)。鏈表是由一組元素以特定的順序組合或鏈接在一起的,不同元素之間在邏輯上相鄰,但是在物理上并不一定相鄰。在維護(hù)一組數(shù)據(jù)集合時(shí),就可以使用鏈表,這一點(diǎn)和數(shù)組很相似2021-11-11
C語(yǔ)言實(shí)現(xiàn)的PNPoly算法代碼例子
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)的PNPoly算法代碼例子,PNPoly算法j是判斷一個(gè)坐標(biāo)點(diǎn)是否在不規(guī)則多邊形內(nèi)部的算法,需要的朋友可以參考下2014-07-07
VC使用編譯時(shí)間作為版本號(hào)標(biāo)識(shí)的方法
這篇文章主要介紹了VC使用編譯時(shí)間作為版本號(hào)標(biāo)識(shí)的方法,需要的朋友可以參考下2017-03-03
C/C++實(shí)現(xiàn)快速排序算法的思路及原理解析
這篇文章主要介紹了C/C++實(shí)現(xiàn)快速排序算法的思路及原理解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
帶你了解C語(yǔ)言的數(shù)據(jù)的存儲(chǔ)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言的數(shù)據(jù)的存儲(chǔ),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能給你帶來(lái)幫助2021-08-08
詳解C語(yǔ)言內(nèi)核中的鏈表與結(jié)構(gòu)體
Windows內(nèi)核中是無(wú)法使用vector容器等數(shù)據(jù)結(jié)構(gòu)的,當(dāng)我們需要保存一個(gè)結(jié)構(gòu)體數(shù)組時(shí),就需要使用內(nèi)核中提供的專用鏈表結(jié)構(gòu)。本文分享了幾個(gè)內(nèi)核中使用鏈表存儲(chǔ)多個(gè)結(jié)構(gòu)體的通用案例,希望對(duì)你有所幫助2022-09-09
C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之Hash散列表
這篇文章主要介紹了C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之Hash散列表,散列表(哈希表)其思想主要是基于數(shù)組支持按照下標(biāo)隨機(jī)訪問(wèn)數(shù)據(jù),時(shí)間復(fù)雜度為O(1)的特性,可以說(shuō)是數(shù)組的一種拓展,需要的朋友可以參考下2023-08-08
C語(yǔ)言使用ffmpeg實(shí)現(xiàn)單線程異步的視頻播放器
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言如何使用ffmpeg實(shí)現(xiàn)單線程異步的視頻播放器功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-12-12

