我最近写一个项目的时候需要涉及到udp传输图片,udp发送速度快,但易丢包,而发送图片过程中丢包将导致图片无法打开,因此需要对包进行处理,并每收到一包回复一个标志位,保证正确接收每一包。
服务端代码
Package.h
#ifndef __PACKAGE_H__
#define __PACKAGE_H__
#include <string.h>
#include <iostream>
using namespace std;
struct DataPackage{
/**
* 内容名字 忽略即可
*/
char contentName[50];
/**
* 初步定于1400字节
*/
char data[1400];
/**
* 数据长度
*/
int datasize;
/**
* 包序号,排序用的
*/
int segmentNum;
/**
* 是否为最后一个包
* 不是: end = 0
* 是: end = 1
*/
int end;
};
#endif
udpsocket.h
#pragma once
#ifndef UDPSOCKET_H
#define UDPSOCKET_H
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include<time.h>
#include<string>
#include<unistd.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<iostream>
using std::string;
#define BUFFER_SIZE 1400
class UDPSocket
{
public:
UDPSocket();
~UDPSocket();
/**
* @brief sendImage
* @param fileName
*/
void sendImage(const string& fileName);
private:
/**
* @brief create
* @param mcastip
* @param mcastport
* @return
*/
int create(string mcastip,int mcastport);
/**
* @brief sendbuf
* @param buf
* @param buflen
* @param destip
* @param destport
* @return
*/
int sendbuf(char *buf,int buflen,string destip,unsigned short destport);
/**
* @brief create
* @param port
* @return
*/
int create(unsigned short port);//绑定端口
/**
* @brief create
* @return
*/
int create();
/**
* @brief recvbuf
* @param buf
* @param buflen
* @param srcip
* @param srcport
* @return
*/
int recvbuf(char *buf,int buflen,string&srcip,unsigned short &srcport);
/**
* @brief Close
* @return
*/
int Close();
private:
/**
* @brief sock
*/
int sock;
/**
* @brief m_sock
*/
int m_sock;
};
#endif
udpsocket.cpp
#include "udpsocket.h"
#include "Package.h"
#include <iostream>
using namespace std;
UDPSocket::UDPSocket():
sock(0),
m_sock(0)
{
}
UDPSocket::~UDPSocket()
{
close(sock);
}
void UDPSocket::sendImage(const std::string &fileName)
{
string dstip = "127.0.0.1";
unsigned short dstport = 51002;
create(20021);
string file1;
cout << "Please input file name: " << endl;
cin >> file1;
FILE *fp = fopen(fileName.c_str(),"rb");
if (fp == NULL)
{
cout<<"File:"<<fileName<<" Not Found!"<<endl;
return;
}
DataPackage datapackage;
char readbuffer[BUFFER_SIZE];
bzero(readbuffer,BUFFER_SIZE);
int file_block_length = 0;
int count = 0;
while( (file_block_length = fread(readbuffer, sizeof(char), BUFFER_SIZE, fp)) > 0)
{
memcpy(datapackage.data,readbuffer,BUFFER_SIZE);
strcpy(datapackage.contentName,"55.png");
datapackage.datasize = file_block_length;
datapackage.segmentNum = count;
if(file_block_length < BUFFER_SIZE)
datapackage.end = 1;
else
datapackage.end = 0;
char sendbuffer[BUFFER_SIZE+100];
memcpy(sendbuffer, &datapackage, sizeof(sendbuffer));
sendbuf(sendbuffer, sizeof(sendbuffer), dstip, dstport);
char recvBuf;
string srcip_;
unsigned short sport_;
int lenrecv;
while(lenrecv = recvbuf(&recvBuf, 1, srcip_, sport_))
{
if(lenrecv < 0){
cout << "[Error] udpSocket recv error" << endl;
return;
}
if(recvBuf == 0x00){
sendbuf(sendbuffer, sizeof(sendbuffer), dstip, dstport);
}
else{
break;
}
}
memset(&datapackage,0,sizeof (datapackage));
count++;
}
cout << "Send Image file success!" << endl;
cout << "Send data package count:" << count <<endl;
fclose(fp);
}
int
UDPSocket::create()
{
sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock<0)
{
std::cout<<"socket initialize error"<<std::endl;
close(sock);
return -1;
}
return sock;
}
int
UDPSocket::create(unsigned short port)
{
//struct sockaddr_in localaddr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
{
std::cout << "socket initialize error" << std::endl;
close(sock);
return -1;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
//int addr_len = sizeof(addr);
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, NULL, 0);
int ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if (ret == -1)
{
std::cout << "socket bind error" << std::endl;
close(sock);
return -1;
}
return sock;
}
int
UDPSocket::create(string mcastip,int mcastport)
{
struct sockaddr_in addr;
struct ip_mreq mreq;
u_int yes = 1;
if ((m_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
std::cout << "mcastsocket error" << std::endl;
return -1;
}
if (setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, &yes,sizeof(yes)) < 0)
{
std::cout << "setsockopt error" << std::endl;
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(mcastport);
if (bind(m_sock, (struct sockaddr*)&addr, sizeof(addr))!=0)
{
std::cout << "msockt bind error" << std::endl;
return -1;
}
mreq.imr_multiaddr.s_addr = inet_addr(mcastip.c_str());
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(m_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
{
std::cout << "msockt bind error" << std::endl;
return -1;
}
return m_sock;
}
int
UDPSocket::sendbuf(char *buf,int buflen,string destip,unsigned short destport)
{
struct sockaddr_in dstaddr;
memset(&dstaddr, 0, sizeof(dstaddr));
dstaddr.sin_family = AF_INET;
dstaddr.sin_addr.s_addr = inet_addr(destip.c_str());
dstaddr.sin_port = htons(destport);
return sendto(sock, buf, buflen, 0, (struct sockaddr *)&dstaddr, sizeof(dstaddr));
}
int
UDPSocket::recvbuf(char *buf, int buflen, string &srcip, unsigned short &srcport)
{
struct sockaddr_in srcaddr;
int from_addr_len = sizeof(struct sockaddr);
int recvsize;
recvsize = recvfrom(sock,buf,buflen,0,(struct sockaddr *)&srcaddr,(socklen_t *)&from_addr_len);
if (recvsize > 0)
{
srcip = inet_ntoa(srcaddr.sin_addr);
srcport = ntohs(srcaddr.sin_port);
}
return recvsize;
}
int
UDPSocket::Close()
{
close(sock);
return 0;
}
main.cpp
#include <iostream>
#include "udpsocket.h"
using namespace std;
int main()
{
UDPSocket udp_socket;
udp_socket.sendImage("/home/examyes/Pictures/55.png");
return 0;
}
接收端代码
Package.h
#ifndef __PACKAGE_H__
#define __PACKAGE_H__
#include <string.h>
#include <iostream>
using namespace std;
struct DataPackage{
/**
* 内容名字 忽略即可
*/
char contentName[50];
/**
* 初步定于1400字节
*/
char data[1400];
/**
* 数据长度
*/
int datasize;
/**
* 包序号,排序用的
*/
int segmentNum;
/**
* 是否为最后一个包
* 不是: end = 0
* 是: end = 1
*/
int end;
};
#endif
udpsocket.h
#pragma once
#ifndef UDPSOCKET_H
#define UDPSOCKET_H
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include<string>
#include<unistd.h>
#include<stdlib.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<iostream>
using std::string;
#define BUFFER_SIZE 1400
class UDPSocket
{
public:
UDPSocket();
~UDPSocket();
/**
* @brief recvImage
* @param filename
*/
void recvImage(const string &filename);
private:
/**
* @brief create
* @param port
* @return
*/
int create(unsigned short port);//绑定端口
/**
* @brief create
* @return
*/
int create();
/**
* @brief create
* @param mcastip
* @param mcastport
* @return
*/
int create(string mcastip,int mcastport);
/**
* @brief sendbuf
* @param buf
* @param buflen
* @param destip
* @param destport
* @return
*/
int sendbuf(char *buf,int buflen,string destip,unsigned short destport);
/**
* @brief recvbuf
* @param buf
* @param buflen
* @param srcip
* @param srcport
* @return
*/
int recvbuf(char *buf,int buflen,string&srcip,unsigned short &srcport);
/**
* @brief Close
* @return
*/
int Close();
private:
/**
* @brief sock
*/
int sock;
/**
* @brief m_sock
*/
int m_sock;
};
#endif
udpsocket.cpp
#include "udpsocket.h"
#include "Package.h"
using namespace std;
UDPSocket::UDPSocket()
{
}
UDPSocket::~UDPSocket()
{
close(sock);
}
void UDPSocket::recvImage(const std::string &filename)
{
FILE *outfile = fopen(filename.c_str(),"wb");
string dstip = "127.0.0.1";
unsigned short dstport = 20021;
create(51002);
char recvBuf[BUFFER_SIZE+100];
string srcip_;
unsigned short sport_;
int lenrecv;
DataPackage datapackage;
int count = 0;
while (true)
{
lenrecv = recvbuf(recvBuf, BUFFER_SIZE+100, srcip_, sport_);
if(lenrecv < 0){
cout << "[Error] udpSocket recv error" << endl;
break;
}
memcpy(&datapackage, recvBuf, sizeof(DataPackage));
char ack = 0x00;
if(count != datapackage.segmentNum){
sendbuf(&ack,sizeof (ack), dstip, dstport);
continue;
}
else{
ack = 0x01;
count++;
sendbuf(&ack,sizeof (ack), dstip, dstport);
}
int write_length = fwrite(datapackage.data, sizeof(char), datapackage.datasize, outfile);
if(write_length < datapackage.datasize){
cout<<"File write error!"<<endl;
break;
}
//判断是不是最后一行
if(datapackage.end == 1)
break;
memset(&datapackage,0,sizeof (datapackage));
}
cout << "Recv Image file success!" << endl;
cout << "Recv data package count:" << count <<endl;
fclose(outfile);
}
int
UDPSocket::create()
{
sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock<0)
{
std::cout<<"socket initialize error"<<std::endl;
close(sock);
return -1;
}
return sock;
}
int
UDPSocket::create(unsigned short port)
{
//struct sockaddr_in localaddr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0)
{
std::cout << "socket initialize error" << std::endl;
close(sock);
return -1;
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
//int addr_len = sizeof(addr);
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, NULL, 0);
int ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if (ret == -1)
{
std::cout << "socket bind error" << std::endl;
close(sock);
return -1;
}
return sock;
}
int
UDPSocket::create(string mcastip,int mcastport)
{
struct sockaddr_in addr;
struct ip_mreq mreq;
u_int yes = 1;
if ((m_sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
std::cout << "mcastsocket error" << std::endl;
return -1;
}
if (setsockopt(m_sock, SOL_SOCKET, SO_REUSEADDR, &yes,sizeof(yes)) < 0)
{
std::cout << "setsockopt error" << std::endl;
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(mcastport);
if (bind(m_sock, (struct sockaddr*)&addr, sizeof(addr))!=0)
{
std::cout << "msockt bind error" << std::endl;
return -1;
}
mreq.imr_multiaddr.s_addr = inet_addr(mcastip.c_str());
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(m_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0)
{
std::cout << "msockt bind error" << std::endl;
return -1;
}
return m_sock;
}
int
UDPSocket::sendbuf(char *buf,int buflen,string destip,unsigned short destport)
{
struct sockaddr_in dstaddr;
memset(&dstaddr, 0, sizeof(dstaddr));
dstaddr.sin_family = AF_INET;
dstaddr.sin_addr.s_addr = inet_addr(destip.c_str());
dstaddr.sin_port = htons(destport);
return sendto(sock, buf, buflen, 0, (struct sockaddr *)&dstaddr, sizeof(dstaddr));
}
int
UDPSocket::recvbuf(char *buf, int buflen, string &srcip, unsigned short &srcport)
{
struct sockaddr_in srcaddr;
int from_addr_len = sizeof(struct sockaddr);
int recvsize;
recvsize = recvfrom(sock,buf,buflen,0,(struct sockaddr *)&srcaddr,(socklen_t *)&from_addr_len);
if (recvsize > 0)
{
srcip = inet_ntoa(srcaddr.sin_addr);
srcport = ntohs(srcaddr.sin_port);
}
return recvsize;
}
int
UDPSocket::Close()
{
close(sock);
return 0;
}