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

#include

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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#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

#include

#include

#include

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

#include

#include

#include

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

#include

#include

#include

#include

#include

#include

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文件。

参考文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: