1.开发环境:Win10+Cion
2.文件结构:
发送端:Package.h定义了发送数据的格式及内容,UDPSocket.h和UDPSocket.cpp对UDP发送数据进行了函数封装,man.cpp是程序入口,执行发送数据逻辑。
接收端与之类似。
3.源文件:Package.h
//
// Created by Guangsheng Li on 2023/5/8.
//
#ifndef __PACKAGE_H__
#define __PACKAGE_H__
#include <string.h>
#include <iostream>
using namespace std;
struct DataPackage{
/**
* 内容名字 忽略即可
*/
char contentName[100];
/**
* 具体数据,我只是初步定于1400字节,因为考虑到IP的MTU是1500字节
*/
char data[1400];
/**
* 数据长度
*/
int datasize;
/**
* 包序号,排序用的
*/
int segmentNum;
/**
* 是否为最后一个包
* 不是: end = 0
* 是: end = 1
*/
int end;
DataPackage(const char* _contentName, const char* _data, int _size, int _segmentNum, int _end){
strcpy(contentName, _contentName);
strcpy(data, _data);
datasize = _size;
segmentNum = _segmentNum;
end = _end;
}
DataPackage(){}
bool operator==(const DataPackage rhs) const{
//return (this->segmentNum == rhs.segmentNum && this->datasize == rhs.datasize && strlen(this->contentName) == strlen(rhs.contentName) && strncmp(this->contentName, rhs.contentName, sizeof(this->contentName)));
return (strlen(this->contentName) == strlen(rhs.contentName) && strncmp(this->contentName, rhs.contentName, sizeof(this->contentName)) == 0);
}
bool operator < (const DataPackage rhs) const{
string contentstr1 = this->contentName;
string contentstr2 = rhs.contentName;
return contentstr1 < contentstr2;
}
};
#endif
UDPSocket.h
//
// Created by Guangsheng Li on 2023/5/8.
//
#pragma once
#ifndef UDPSOCKET_H
#define UDPSOCKET_H
#include <stdio.h>
#include <string.h>
#include <winsock2.h>
#include <time.h>
#include <string>
#include <unistd.h>
#include <stdlib.h>
#include <windows.h>
#include <sys/types.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib")
using std::string;
class UDPSocket
{
public:
UDPSocket();
~UDPSocket();
int create(unsigned short port);//绑定端口
int create();
int create(string mcastip,int mcastport);
int sendbuf(char *buf,int buflen,string destip,unsigned short destport);
int recvbuf(char *buf,int buflen,string &srcip,unsigned short &srcport);
int Close();
int sock;
int m_sock;
};
#endif
UDPSocket.cpp
#include "UDPSocket.h"
#include "Package.h"
#include <unordered_map>
#include <iostream>
#include <unistd.h>
#include <fstream>
using namespace std;
//传输二进制文件的函数
void sendBinFile(){
string dstip = "162.105.85.198";
unsigned short dstport = 51002;
UDPSocket udpsocket;
udpsocket.create(20022);
string file1;
cout << "Please input file name: " << endl;
cin >> file1;
ifstream in(file1, ios::binary);
if(!in){
cout << "File open error" << endl;
return;
}
int count = 1;
//需要一直读取到文件结束,注意这里不是按行读取,是按长度读取
while (!in.eof())
{
DataPackage datapackage;
string contentName = "pku/eecs/file/" + file1 + "/segment" + to_string(count);
strcpy(datapackage.contentName, contentName.c_str());
in.read(datapackage.data, 1400);
//这句话是核心,表示读取的长度.正常情况是1400,但是最后一次可能小于1400
datapackage.datasize = in.gcount();
cout << datapackage.datasize << endl;
datapackage.segmentNum = count;
if(datapackage.datasize != 1400){
datapackage.end = 1;
}
else{
datapackage.end = 0;
}
char sendbuffer[1500];
memcpy(sendbuffer, &datapackage, sizeof(sendbuffer));
udpsocket.sendbuf(sendbuffer, sizeof(sendbuffer), dstip, dstport);
if(datapackage.end == 1){
break;
}
count++;
}
udpsocket.Close();
}
//传输文本文件的函数
void sendTextFile(){
// string dstip = "162.105.85.198";
string dstip = "127.0.0.1";
unsigned short dstport = 51002;
UDPSocket udpsocket;
udpsocket.create(20021);
string file1;
cout << "Please input file name: " << endl;
cin >> file1;
// file1="C:\\Users\\Guangsheng Li\\Desktop\\test10\\a.txt";
string s="C:\\Users\\Guangsheng Li\\Desktop\\test10\\";
file1=s+file1;
ifstream in(file1);
string filename;
string line;
// getline(in, line);
// cout <<"读取的字符串"<< line;
int count = 1;
//按行读取
while (getline (in, line))
{
DataPackage datapackage;
int i;
for(i = 0; i < line.size(); i++){
datapackage.data[i] = line[i];
}
datapackage.data[i] = '\0';
string contentName = "pku/eecs/file/" + file1 + "/segment" + to_string(count);
strcpy(datapackage.contentName, contentName.c_str());
datapackage.datasize = i + 2;
datapackage.segmentNum = count;
//如果已经读到了最后一行,那么加上标志位
if(in.eof()){
datapackage.end = 1;
}
else{
datapackage.end = 0;
}
char sendbuffer[1500];
memcpy(sendbuffer, &datapackage, sizeof(sendbuffer));
udpsocket.sendbuf(sendbuffer, sizeof(sendbuffer), dstip, dstport);
count++;
}
udpsocket.Close();
}
int main(){
//按照你想测试的函数调用即可
sendTextFile();
// sendBinFile();
return 0;
}
main.cpp
#include "UDPSocket.h"
#include "Package.h"
#include <unordered_map>
#include <iostream>
#include <unistd.h>
#include <fstream>
using namespace std;
//传输二进制文件的函数
void sendBinFile(){
string dstip = "162.105.85.198";
unsigned short dstport = 51002;
UDPSocket udpsocket;
udpsocket.create(20022);
string file1;
cout << "Please input file name: " << endl;
cin >> file1;
ifstream in(file1, ios::binary);
if(!in){
cout << "File open error" << endl;
return;
}
int count = 1;
//需要一直读取到文件结束,注意这里不是按行读取,是按长度读取
while (!in.eof())
{
DataPackage datapackage;
string contentName = "pku/eecs/file/" + file1 + "/segment" + to_string(count);
strcpy(datapackage.contentName, contentName.c_str());
in.read(datapackage.data, 1400);
//这句话是核心,表示读取的长度.正常情况是1400,但是最后一次可能小于1400
datapackage.datasize = in.gcount();
cout << datapackage.datasize << endl;
datapackage.segmentNum = count;
if(datapackage.datasize != 1400){
datapackage.end = 1;
}
else{
datapackage.end = 0;
}
char sendbuffer[1500];
memcpy(sendbuffer, &datapackage, sizeof(sendbuffer));
udpsocket.sendbuf(sendbuffer, sizeof(sendbuffer), dstip, dstport);
if(datapackage.end == 1){
break;
}
count++;
}
udpsocket.Close();
}
//传输文本文件的函数
void sendTextFile(){
// string dstip = "162.105.85.198";
string dstip = "127.0.0.1";
unsigned short dstport = 51002;
UDPSocket udpsocket;
udpsocket.create(20021);
string file1;
cout << "Please input file name: " << endl;
cin >> file1;
// file1="C:\\Users\\Guangsheng Li\\Desktop\\test10\\a.txt";
string s="C:\\Users\\Guangsheng Li\\Desktop\\test10\\";
file1=s+file1;
ifstream in(file1);
string filename;
string line;
// getline(in, line);
// cout <<"读取的字符串"<< line;
int count = 1;
//按行读取
while (getline (in, line))
{
DataPackage datapackage;
int i;
for(i = 0; i < line.size(); i++){
datapackage.data[i] = line[i];
}
datapackage.data[i] = '\0';
string contentName = "pku/eecs/file/" + file1 + "/segment" + to_string(count);
strcpy(datapackage.contentName, contentName.c_str());
datapackage.datasize = i + 2;
datapackage.segmentNum = count;
//如果已经读到了最后一行,那么加上标志位
if(in.eof()){
datapackage.end = 1;
}
else{
datapackage.end = 0;
}
char sendbuffer[1500];
memcpy(sendbuffer, &datapackage, sizeof(sendbuffer));
udpsocket.sendbuf(sendbuffer, sizeof(sendbuffer), dstip, dstport);
count++;
}
udpsocket.Close();
}
int main(){
//按照你想测试的函数调用即可
sendTextFile();
// sendBinFile();
return 0;
}
4.接收端man.cpp
#include "UDPSocket.h"
#include "Package.h"
#include <unordered_map>
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <fstream>
using namespace std;
//接收二进制文件
void receiveBinFile(char* filename){
ofstream outfile(filename, ios::binary);
UDPSocket udpsocket;
udpsocket.create(51002);
char recvBuf[1500];
string srcip_;
unsigned short sport_;
int lenrecv;
while (true)
{
lenrecv = udpsocket.recvbuf(recvBuf, 1500, srcip_, sport_);
if(lenrecv < 0){
cout << "[Error] udpSocket recv error" << endl;
break;
}
DataPackage datapackage;
memcpy(&datapackage, recvBuf, sizeof(DataPackage));
outfile.write(datapackage.data, datapackage.datasize);
//判断是不是最后一个
if(datapackage.end == 1) break;
}
udpsocket.Close();
outfile.close();
}
//接收文本文件
void receiveTextFile(char* filename){
ofstream outfile(filename);
UDPSocket udpsocket;
udpsocket.create(51002);
char recvBuf[1500];
string srcip_;
unsigned short sport_;
int lenrecv;
while (true)
{
lenrecv = udpsocket.recvbuf(recvBuf, 1500, srcip_, sport_);
if(lenrecv < 0){
cout << "[Error] udpSocket recv error" << endl;
break;
}
DataPackage datapackage;
memcpy(&datapackage, recvBuf, sizeof(DataPackage));
outfile << datapackage.data << endl;
//判断是不是最后一行
if(datapackage.end == 1) break;
}
udpsocket.Close();
outfile.close();
}
int main(){
//按需调用,注意传参数为想要保存的文件名称和地址
receiveTextFile("C:\\Users\\Guangsheng Li\\Desktop\\JIeshou\\b.txt");
// receiveBinFile("11583.mp3");
return 0;
}
启动执行发送端和接收端程序后,发送会通过UDP协议把a.txt文件发送过来,接收端将其写入b.txt文件。