基于Qt編寫的文件傳輸工具
文件傳輸工具
通過發(fā)送udp廣播消息將IP廣播給其他開啟該程序的局域網(wǎng)機(jī)器
收到的廣播消息可以顯示在IP地址列表中,點(diǎn)擊IP地址可以自動(dòng)填充到IP地址欄內(nèi)
選擇文件后點(diǎn)擊發(fā)送可以發(fā)送給指定IP,并能在傳輸過程中顯示進(jìn)度
默認(rèn)端口6001。目前不支持修改,修改端口會(huì)導(dǎo)致網(wǎng)絡(luò)連接失敗。
界面比較簡潔:
部分代碼如下:
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; }
通過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; }
通過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("打開文件:%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語言數(shù)據(jù)結(jié)構(gòu)之單向鏈表詳解分析
鏈表可以說是一種最為基礎(chǔ)的數(shù)據(jù)結(jié)構(gòu)了,而單向鏈表更是基礎(chǔ)中的基礎(chǔ)。鏈表是由一組元素以特定的順序組合或鏈接在一起的,不同元素之間在邏輯上相鄰,但是在物理上并不一定相鄰。在維護(hù)一組數(shù)據(jù)集合時(shí),就可以使用鏈表,這一點(diǎn)和數(shù)組很相似2021-11-11VC使用編譯時(shí)間作為版本號(hào)標(biāo)識(shí)的方法
這篇文章主要介紹了VC使用編譯時(shí)間作為版本號(hào)標(biāo)識(shí)的方法,需要的朋友可以參考下2017-03-03C/C++實(shí)現(xiàn)快速排序算法的思路及原理解析
這篇文章主要介紹了C/C++實(shí)現(xiàn)快速排序算法的思路及原理解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01詳解C語言內(nèi)核中的鏈表與結(jié)構(gòu)體
Windows內(nèi)核中是無法使用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-09C語言數(shù)據(jù)結(jié)構(gòu)之Hash散列表
這篇文章主要介紹了C語言數(shù)據(jù)結(jié)構(gòu)之Hash散列表,散列表(哈希表)其思想主要是基于數(shù)組支持按照下標(biāo)隨機(jī)訪問數(shù)據(jù),時(shí)間復(fù)雜度為O(1)的特性,可以說是數(shù)組的一種拓展,需要的朋友可以參考下2023-08-08C語言使用ffmpeg實(shí)現(xiàn)單線程異步的視頻播放器
這篇文章主要為大家詳細(xì)介紹了C語言如何使用ffmpeg實(shí)現(xiàn)單線程異步的視頻播放器功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以嘗試一下2022-12-12