C++实现通过UDP传输文件
一. 程序說明
1.本程序通過 UDP 來傳輸文件及其管理元數據(文件名、大小和日期等),包括client.cpp和server.cpp,分別是客戶端程序和服務端程序。
2.文件以二進制形式傳輸。
3.由客戶端指定文件目錄,將文件傳送到服務端,除了文件名之外,附帶傳送文件大小、創建時間等信息。
4.獲取文件大小和創建日期的詳細程序可以看C++獲取文件的創建時間和大小
5.客戶端發送完畢后,向服務端發送一條“end”信息,服務端受到后停止監聽。
6.通過UDP傳輸比TCP快,但是UDP不如TCP穩定,可能出現丟包和亂序的情況。這里通過“發-收-發”的方式防止丟包和亂序,即客戶端每發送一條消息,服務端收到后都會回信一條,受到回信后,客戶端再繼續發送,沒有受到則報錯。還有一種實現方式是,利用多線程發送信息,給每次發送的信息編號,服務端檢查收到的信息的編號,以此判斷是否出現亂序或丟包。(暫未完成)
二. 代碼實現
client.cpp:
/*
客戶端程序
客戶端給服務端發送文件,包含管理元數據(文件名、大小和日期)
*/
#include<iostream>
#include<WinSock2.h>
#include<winsock.h>
#include<Windows.h>
#include<string>
#include<cstring>
#include <fstream>
#include <io.h>
#pragma comment(lib,"ws2_32.lib")
#define BUF_SIZE 1024
#define SERVER_ID "127.0.0.1"
#define PATH_LENGTH 20
using namespace std;
char sendBuff[BUF_SIZE];
char recvBuff[BUF_SIZE];
char fileName[PATH_LENGTH];
BOOL getFileTime(HANDLE hFile, LPSTR lpszCreationTime)//獲取文件創建日期
{
?? ?FILETIME ftCreate, ftAccess, ftWrite;
?? ?SYSTEMTIME stUTC1, stLocal1;
?? ?// -------->獲取 FileTime
?? ?if (!GetFileTime(hFile, &ftCreate, &ftAccess, &ftWrite)) {
?? ??? ?cout << "error!" << endl;
?? ??? ?return FALSE;
?? ?}
?? ?//---------> 轉換: FileTime --> LocalTime
?? ?FileTimeToSystemTime(&ftCreate, &stUTC1);
?? ?SystemTimeToTzSpecificLocalTime(NULL, &stUTC1, &stLocal1);
?? ?// ---------> Show the ?date and time.
?? ?sprintf(lpszCreationTime, "%02d/%02d/%02d ?%02d:%02d",
?? ??? ?stLocal1.wYear, stLocal1.wMonth, stLocal1.wDay,
?? ??? ?stLocal1.wHour, stLocal1.wMinute);
?? ?return TRUE;
}
int main() {
?? ?WSADATA wsa;
?? ?if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
?? ??? ?cout << "Initialization failed." << endl;
?? ??? ?return -1;
?? ?}
?? ?SOCKET client = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
?? ?if (client == -1) {
?? ??? ?cout << "Socket failed." << endl;
?? ??? ?return -1;
?? ?}
?? ?sockaddr_in sadr;
?? ?sadr.sin_family = AF_INET;
?? ?sadr.sin_port = htons(5000);
?? ?sadr.sin_addr.S_un.S_addr = inet_addr(SERVER_ID);
?? ?int nAddrlen = sizeof(sadr);
?? ?while (true) {
?? ??? ?cout << "---------------------SENDING...---------------------" << endl;
?? ??? ?cout << "Please input the filename: " << endl;
?? ??? ?cin >> fileName;
?? ??? ?FILE *fp;
?? ??? ?if (!(fp = fopen(fileName, "rb"))) {
?? ??? ??? ?cout << "Fail to open file." << endl;
?? ??? ??? ?continue;
?? ??? ?}
?? ??? ?//先傳送文件名
?? ??? ?sendto(client, fileName, strlen(fileName), 0, (sockaddr*)&sadr, sizeof(sadr));
?? ??? ?int length;
?? ??? ?int ret;
?? ??? ?while ((length = fread(sendBuff, 1, BUF_SIZE, fp)) > 0) {
?? ??? ??? ?ret = sendto(client, sendBuff, length, 0, (sockaddr*)&sadr, sizeof(sadr));
?? ??? ??? ?if (!ret) {
?? ??? ??? ??? ?cout << "An error occurred while sending." << endl;
?? ??? ??? ??? ?return -1;
?? ??? ??? ?}
?? ??? ??? ?ret = recvfrom(client, recvBuff, BUF_SIZE, 0, (sockaddr*)&sadr, &nAddrlen);
?? ??? ??? ?if (!ret) {
?? ??? ??? ??? ?cout << "Fail to receive." << endl;
?? ??? ??? ??? ?return -1;
?? ??? ??? ?}
?? ??? ??? ?else {
?? ??? ??? ??? ?if (strcmp(recvBuff, "success")) {
?? ??? ??? ??? ??? ?cout << "Fail to receive." << endl;
?? ??? ??? ??? ??? ?return -1;
?? ??? ??? ??? ?}
?? ??? ??? ?}
?? ??? ?}
?? ??? ?//傳送文件發送結束信息
?? ??? ?char end_flag[10] = "end";
?? ??? ?ret = sendto(client, end_flag, length, 0, (sockaddr*)&sadr, sizeof(sadr));
?? ??? ?//獲取文件創建時間和大小
?? ??? ?HANDLE hFile;
?? ??? ?TCHAR szCreationTime[30];
?? ??? ?hFile = CreateFile(fileName, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
?? ??? ?getFileTime(hFile, szCreationTime);
?? ??? ?if (hFile == INVALID_HANDLE_VALUE) {
?? ??? ??? ?cout << "error!" << endl;
?? ??? ??? ?return -1;
?? ??? ?}
?? ??? ?int size = GetFileSize(hFile, NULL);
?? ??? ?//傳送時間和大小信息
?? ??? ?ret = sendto(client, szCreationTime, 30, 0, (sockaddr*)&sadr, sizeof(sadr));
?? ??? ?size = size / 1024 + 1;//B轉KB
?? ??? ?string tempSize = to_string(size);
?? ??? ?tempSize += "KB";
?? ??? ?char fileSize[20];
?? ??? ?strcpy(fileSize, tempSize.c_str());
?? ??? ?ret = sendto(client, fileSize, 20, 0, (sockaddr*)&sadr, sizeof(sadr));
?? ??? ?cout << "successfully sent!" << endl;
?? ??? ?fclose(fp);
?? ??? ?CloseHandle(hFile);
?? ?}
?? ?closesocket(client);
?? ?WSACleanup();
?? ?return 0;
}
server.cpp:
/*
服務端程序
接收從客戶端發送的文件,包含管理元數據(文件名、大小和日期)
*/
#include<iostream>
#include<WinSock2.h>
#include<winsock.h>
#pragma comment(lib,"ws2_32.lib")
#define BUF_SIZE 1024
#define PATH_LENGTH 20
using namespace std;
char sendBuff[BUF_SIZE];
char recvBuff[BUF_SIZE];
char fileName[PATH_LENGTH];
int main() {
?? ?WSADATA wsa;
?? ?if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
?? ??? ?cout << "Initialization failed." << endl;
?? ??? ?return -1;
?? ?}
?? ?SOCKET server = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
?? ?if (server == -1) {
?? ??? ?cout << "Socket failed." << endl;
?? ??? ?return -1;
?? ?}
?? ?sockaddr_in my_addr, remote_addr;
?? ?int nAddrlen = sizeof(remote_addr);
?? ?my_addr.sin_family = AF_INET;
?? ?my_addr.sin_port = htons(5000);
?? ?my_addr.sin_addr.S_un.S_addr = INADDR_ANY;
?? ?if (::bind(server, (sockaddr*)&my_addr, sizeof(my_addr)) == SOCKET_ERROR) {
?? ??? ?cout << "Bind error!" << endl;
?? ??? ?return -1;
?? ?}
?? ?while (true) {
?? ??? ?cout << "---------------------RECEIVING...---------------------" << endl;
?? ??? ?//接收文件名
?? ??? ?int ret = recvfrom(server, fileName, BUF_SIZE, 0, (sockaddr*)&remote_addr, &nAddrlen);
?? ??? ?cout << "Filename: " << fileName << endl;
?? ??? ?errno_t err;
?? ??? ?FILE *fp;
?? ??? ?if ((err = fopen_s(&fp, fileName, "wb")) < 0) {
?? ??? ??? ?cout << "Create failed." << endl;
?? ??? ??? ?return -1;
?? ??? ?}
?? ??? ?int length;
?? ??? ?while ((length = recvfrom(server, recvBuff, BUF_SIZE, 0, (sockaddr*)&remote_addr, &nAddrlen))) {
?? ??? ??? ?if (!strcmp(recvBuff, "end"))//接收結束信息
?? ??? ??? ??? ?break;
?? ??? ??? ?if (length == 0) {
?? ??? ??? ??? ?cout << "An error occurred while receiving." << endl;
?? ??? ??? ??? ?return -1;
?? ??? ??? ?}
?? ??? ??? ?int ret = fwrite(recvBuff, 1, length, fp);
?? ??? ??? ?if (ret < length) {
?? ??? ??? ??? ?cout << "Write failed." << endl;
?? ??? ??? ??? ?return -1;
?? ??? ??? ?}
?? ??? ??? ?sendto(server, "success", sizeof("success") + 1, 0, (SOCKADDR*)&remote_addr, sizeof(remote_addr));
?? ??? ?}
?? ??? ?//接收文件創建日期、大小信息
?? ??? ?char creationTime[30];
?? ??? ?char fileSize[20];
?? ??? ?recvfrom(server, creationTime, 30, 0, (sockaddr*)&remote_addr, &nAddrlen);
?? ??? ?recvfrom(server, fileSize, 20, 0, (sockaddr*)&remote_addr, &nAddrlen);
?? ??? ?cout << "Creation Time:" << creationTime << endl;
?? ??? ?cout << "Size:" << fileSize << endl;
?? ??? ?cout << "Successfully received!" << endl;
?? ??? ?fclose(fp);
?? ?}
?? ?closesocket(server);
?? ?WSACleanup();
?? ?return 0;
}
?
總結
以上是生活随笔為你收集整理的C++实现通过UDP传输文件的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: apache sgoop 导入数据到
- 下一篇: s3c2440移植MQTT