技术文章分享|UDP文件传输
UDP简介:
UDP是用户数据报协议(User Datagram Protocol),它为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。
UDP报文没有可靠性保证、顺序保证和流量控制字段等,可靠性较差。但在数据传输过程中延迟小、数据传输效率高,适合对可靠性要求不高的应用程序,或者可以保障可靠性的应用程序,如DNS、TFTP、SNMP等。一般应用于:周期性的状态信息、图片和视频数据传输、局域网内数据传输。
UDP文件传输模型思路:
作为传输层的协议之一,我们可以用UDP传输一些文件或其他数据。
1. 首先以fstat函数与fopen/fread等文件操作函数获取文件信息,如:文件内容、文件大小、文件名等具体信息。
2. 然后将获取的文件信息以UDP形式传输至接收端。
除UDP所需函数外,需要用到的函数介绍如下:
int stat(const char *path, struct stat *buf)
作用:获取文件信息
参数:文件路径(名),struct stat 类型的结构体
int fstat (int filedes, struct *buf);
作用:由文件描述符取得文件的状态。
解析:fstat() 用来将参数filedes 所指向的文件状态复制到参数buf 所指向的结构中(struct stat), fstat() 与stat() 作用完全相同,不同之处在于传入的参数为已打开的文件描述符
返回值:执行成功返回0,失败返回-1,错误代码保存在errno中
编码如下:
test.h:
#ifndef __TEST_H
#define __TEST_H
#include <string.h>
enum TYPE // 定义枚举类型,根据类型不同,接收数据时做不同处理
{
NAME,
SIZE,
TYPE,
DATA,
ACK
};
struct file // 定义文件结构体,传输数据时,解析其内容
{
int idx;
int len;
int type;
char data[1024];
};
#endif
recv.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include "test.h"
#include <sys/stat.h>
int main()
{
int sock = socket( AF_INET, SOCK_DGRAM, 0 );
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons( 10010 );
local.sin_addr.s_addr = inet_addr( "127.0.0.1" );
bind( sock, (struct sockaddr *)&local, sizeof(local) );
struct sockaddr_in addr;
int len = sizeof( addr );
while( 1 )
{
struct file stat;
recvfrom( sock, &stat, sizeof(stat), 0, (struct sockaddr *)&addr, &len );
if( stat.type == NAME ) // 根据类型不同,做不同处理,解析数据并输出
{
printf( "name is %s \n", stat.data );
}
else if( stat.type == SIZE )
{
int size = *(int *)stat.data;
printf( "size is %d \n", size );
}
else if( stat.type == DATA )
{
printf( "data is \n%s \n", stat.data );
}
}
close( sock );
return 0;
}
send.c:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include "test.h"
#include <sys/stat.h>
#include <fcntl.h>
int main( int argc, char *argv[] )
{
int sock = socket( AF_INET, SOCK_DGRAM, 0 );
struct sockaddr_in local;
local.sin_family = AF_INET;
local.sin_port = htons( 10086 );
local.sin_addr.s_addr = inet_addr( "127.0.0.1" );
bind( sock, (struct sockaddr *)&local, sizeof(local) );
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons( 10010 );
addr.sin_addr.s_addr = inet_addr( "127.0.0.1" );
// name 发送文件名字
struct file stat;
stat.idx = 0;
stat.len = strlen(argv[1]);
stat.type = NAME;
strcpy( stat.data, argv[1] );
sendto( sock, &stat, sizeof(stat), 0, (struct sockaddr *)&addr, sizeof(addr) );
// size 发送文件大小
stat.idx = 1;
stat.type = SIZE;
int fd = open( argv[1], O_RDONLY );
struct stat buf;
fstat( fd, &buf ); // 获取文件具体数据,比如大小
int size = buf.st_size;
memcpy( stat.data, &size, 4 );
sendto( sock, &stat, sizeof(stat), 0, (struct sockaddr *)&addr, sizeof(addr) );
// data 发送文件内容
stat.idx = 2;
stat.type = DATA;
while( 1 )
{
char buf[1024] = {0};
int ret = read(fd, buf, sizeof(buf)); // 读取文件内容
if( ret <= 0 )
{
break;
}
else
{
memcpy(stat.data, buf, sizeof(buf));
sendto( sock, &stat, sizeof(stat), 0, (struct sockaddr *)&addr, sizeof(addr) ); // 发送内容
}
}
printf("send complete\n");
close( sock );
return 0;
}