我们知道,用TCP实现文件传输很简单。相对于TCP,因为UDP是面向无连接、不可靠的传输协议,所以我们需要考虑丢包后发先至(包的顺序)的问题,所以我们想要实现UDP传输文件,则需要解决这两个问题。方法就是给数据包编号,按照包的顺序接收并存储,接收端接收到数据包后发送确认信息给发送端,发送端接收确认数据以后再继续发送下一个包,如果接收端收到的数据包的编号不是期望的编号,则要求发送端重新发送

下面是我用linux C实现的一个Demo,定义一个包的结构体,其中包含数据和包头,包头里包含包的编号数据大小,经过测试,传输一个视频文件,传送成功。

代码:

/*************************************************************************
> File Name: server.c
> Author: SongLee
> E-mail: lisong.shine@qq.com
> Created Time: 2014年05月11日 星期日 19时55分49秒
> Personal Blog: http://songlee24.github.io
************************************************************************/
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<netdb.h>
#include<stdarg.h>
#include<string.h> #define SERVER_PORT 8000
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512 /* 包头 */
typedef struct
{
int id;
int buf_size;
}PackInfo; /* 接收包 */
struct SendPack
{
PackInfo head;
char buf[BUFFER_SIZE];
} data; int main()
{
/* 发送id */
int send_id = 0; /* 接收id */
int receive_id = 0; /* 创建UDP套接口 */
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(SERVER_PORT); /* 创建socket */
int server_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if(server_socket_fd == -1)
{
perror("Create Socket Failed:");
exit(1);
} /* 绑定套接口 */
if(-1 == (bind(server_socket_fd,(struct sockaddr*)&server_addr,sizeof(server_addr))))
{
perror("Server Bind Failed:");
exit(1);
} /* 数据传输 */
while(1)
{
/* 定义一个地址,用于捕获客户端地址 */
struct sockaddr_in client_addr;
socklen_t client_addr_length = sizeof(client_addr); /* 接收数据 */
char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
if(recvfrom(server_socket_fd, buffer, BUFFER_SIZE,0,(struct sockaddr*)&client_addr, &client_addr_length) == -1)
{
perror("Receive Data Failed:");
exit(1);
} /* 从buffer中拷贝出file_name */
char file_name[FILE_NAME_MAX_SIZE+1];
bzero(file_name,FILE_NAME_MAX_SIZE+1);
strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));
printf("%s\n", file_name); /* 打开文件 */
FILE *fp = fopen(file_name, "r");
if(NULL == fp)
{
printf("File:%s Not Found.\n", file_name);
}
else
{
int len = 0;
/* 每读取一段数据,便将其发给客户端 */
while(1)
{
PackInfo pack_info; if(receive_id == send_id)
{
++send_id;
if((len = fread(data.buf, sizeof(char), BUFFER_SIZE, fp)) > 0)
{
data.head.id = send_id; /* 发送id放进包头,用于标记顺序 */
data.head.buf_size = len; /* 记录数据长度 */
if(sendto(server_socket_fd, (char*)&data, sizeof(data), 0, (struct sockaddr*)&client_addr, client_addr_length) < 0)
{
perror("Send File Failed:");
break;
}
/* 接收确认消息 */
recvfrom(server_socket_fd, (char*)&pack_info, sizeof(pack_info), 0, (struct sockaddr*)&client_addr, &client_addr_length);
receive_id = pack_info.id;
}
else
{
break;
}
}
else
{
/* 如果接收的id和发送的id不相同,重新发送 */
if(sendto(server_socket_fd, (char*)&data, sizeof(data), 0, (struct sockaddr*)&client_addr, client_addr_length) < 0)
{
perror("Send File Failed:");
break;
}
/* 接收确认消息 */
recvfrom(server_socket_fd, (char*)&pack_info, sizeof(pack_info), 0, (struct sockaddr*)&client_addr, &client_addr_length);
receive_id = pack_info.id;
}
}
/* 关闭文件 */
fclose(fp);
printf("File:%s Transfer Successful!\n", file_name);
}
}
close(server_socket_fd);
return 0;
}

/*************************************************************************
> File Name: client.c
> Author: SongLee
> E-mail: lisong.shine@qq.com
> Created Time: 2014年05月11日 星期日 21时53分39秒
> Personal Blog: http://songlee24.github.io
************************************************************************/
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<netdb.h>
#include<stdarg.h>
#include<string.h> #define SERVER_PORT 8000
#define BUFFER_SIZE 1024
#define FILE_NAME_MAX_SIZE 512 /* 包头 */
typedef struct
{
int id;
int buf_size;
}PackInfo; /* 接收包 */
struct RecvPack
{
PackInfo head;
char buf[BUFFER_SIZE];
} data; int main()
{
int id = 1; /* 服务端地址 */
struct sockaddr_in server_addr;
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
server_addr.sin_port = htons(SERVER_PORT);
socklen_t server_addr_length = sizeof(server_addr); /* 创建socket */
int client_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
if(client_socket_fd < 0)
{
perror("Create Socket Failed:");
exit(1);
} /* 输入文件名到缓冲区 */
char file_name[FILE_NAME_MAX_SIZE+1];
bzero(file_name, FILE_NAME_MAX_SIZE+1);
printf("Please Input File Name On Server: ");
scanf("%s", file_name); char buffer[BUFFER_SIZE];
bzero(buffer, BUFFER_SIZE);
strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name)); /* 发送文件名 */
if(sendto(client_socket_fd, buffer, BUFFER_SIZE,0,(struct sockaddr*)&server_addr,server_addr_length) < 0)
{
perror("Send File Name Failed:");
exit(1);
} /* 打开文件,准备写入 */
FILE *fp = fopen(file_name, "w");
if(NULL == fp)
{
printf("File:\t%s Can Not Open To Write\n", file_name);
exit(1);
} /* 从服务器接收数据,并写入文件 */
int len = 0;
while(1)
{
PackInfo pack_info; if((len = recvfrom(client_socket_fd, (char*)&data, sizeof(data), 0, (struct sockaddr*)&server_addr,&server_addr_length)) > 0)
{
if(data.head.id == id)
{
pack_info.id = data.head.id;
pack_info.buf_size = data.head.buf_size;
++id;
/* 发送数据包确认信息 */
if(sendto(client_socket_fd, (char*)&pack_info, sizeof(pack_info), 0, (struct sockaddr*)&server_addr, server_addr_length) < 0)
{
printf("Send confirm information failed!");
}
/* 写入文件 */
if(fwrite(data.buf, sizeof(char), data.head.buf_size, fp) < data.head.buf_size)
{
printf("File:\t%s Write Failed\n", file_name);
break;
}
}
else if(data.head.id < id) /* 如果是重发的包 */
{
pack_info.id = data.head.id;
pack_info.buf_size = data.head.buf_size;
/* 重发数据包确认信息 */
if(sendto(client_socket_fd, (char*)&pack_info, sizeof(pack_info), 0, (struct sockaddr*)&server_addr, server_addr_length) < 0)
{
printf("Send confirm information failed!");
}
}
else
{ }
}
else
{
break;
}
} printf("Receive File:\t%s From Server IP Successful!\n", file_name);
fclose(fp);
close(client_socket_fd);
return 0;
}

Linux网络编程:UDP实现可靠的文件传输的更多相关文章

  1. 网络编程 - socket通信/粘包/文件传输/udp - 总结

    socket通信 1.简单的套接字通信 import socket phone = socket.socket(socket.AF_INET,socket.SOCK_STREAM) phone.bin ...

  2. Linux网络编程:UDP Socket编程范例

    TCP协议提供的是一种可靠的,复杂的,面向连接的数据流(SOCK_STREAM)传输服务,它通过三段式握手过程建立连接.TCP有一种"重传确认"机制,即接收端收到数据后要发出一个肯 ...

  3. TCP/UDP Linux网络编程详解

    本文主要记录TCP/UDP网络编程的基础知识,采用TCP/UDP实现宿主机和目标机之间的网络通信. 内容目录 1. 目标2.Linux网络编程基础2.1 嵌套字2.2 端口2.3 网络地址2.3.1 ...

  4. linux网络编程-(socket套接字编程UDP传输)

    今天我们来介绍一下在linux网络环境下使用socket套接字实现两个进程下文件的上传,下载,和退出操作! 在socket套接字编程中,我们当然可以基于TCP的传输协议来进行传输,但是在文件的传输中, ...

  5. Linux网络编程10——使用UDP实现五子棋对战

    思路 1. 通信 为了同步双方的棋盘,每当一方在棋盘上落子之后,都需要发送给对方一个msg消息,让对方知道落子位置.msg结构体如下: /* 用于发给对方的信息 */ typedef struct t ...

  6. linux网络编程_1

    本文属于转载,稍有改动,以利于学习. (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个 ...

  7. Linux网络编程入门 (转载)

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  8. [转] - Linux网络编程 -- 网络知识介绍

    (一)Linux网络编程--网络知识介绍 Linux网络编程--网络知识介绍客户端和服务端         网络程序和普通的程序有一个最大的区别是网络程序是由两个部分组成的--客户端和服务器端. 客户 ...

  9. Linux C 程序 Linux网络编程(21)

    Linux网络编程网络编程必备的理论基础网络模型,地址,端口,TCP/IP协议 TCP/IP协议是目前世界上使用最广泛的网络通信协议日常中的大部分应用使用该系列协议(浏览网页,收发电子邮件,QQ聊天等 ...

随机推荐

  1. bash 博弈

    转载并修改自: http://www.cnblogs.com/wulangzhou/archive/2013/03/14/2959660.html 简单的取拿游戏一堆石子(或者其它的什么东西),下面是 ...

  2. anime.js 实战:实现一个带有描边动画效果的复选框

    在网页或者是APP的开发中,动画运用得当可以起到锦上添花的作用.正确使用动画,不但可以有助于用户理解交互的作用,还可以大大提高网页应用的魅力和使用体验.并且在现在的网页开发中,动画已经成为了一个设计的 ...

  3. AVR单片机8位数码管显示的程序实现

    AVR单片机8位数码管显示的程序实现 转载:http://www.sohu.com/a/117255149_119709   2016-10-26 16:30 我们接着来完成 数码管的显示实验.现在我 ...

  4. <mybatis:scan>与<MapperScannerConfigurer/>

    使用Mybatis作为持久层的框架,对dao层的bean对象的注解扫描有两种方式:<mybatis:san>.<MapperScannerConfigurer> 一:<m ...

  5. 三维重建:GitHub百度Apollo 2.0

    GitHub:https://github.com/ApolloAuto/apollo 1. 关于Apollo的数据:Apollo的数据会如何开放? 自动驾驶数据将包括具有高分辨率图像和像素级别标注的 ...

  6. python3 操作excel表

    python操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库可从这里下载https://pypi.python.org/pypi.下面分别记录py ...

  7. 00JAVA EE

    JAVA EE 三层架构 我们的开发架构一般都是基于两种形式,一种是C/S架构,也就是客户端/服务器,另一种是B/S架构,也就是浏览器服务器.在JavaEE开发中,几乎全都是基于B/S架构的开发.那么 ...

  8. 3D NAND闪存是个啥?让国内如此疯狂

    Repost: https://news.mydrivers.com/1/477/477251.htm 上个月底武汉新芯科技主导的国家级存储器产业基地正式动工,在大基金的支持下该项目将投资240亿美元 ...

  9. xmpp 消息和好友上下线(3)

    原始地址:XMPPFrameWork IOS 开发(四) 消息 //收到消息 - (void)xmppStream:(XMPPStream *)sender didReceiveMessage:(XM ...

  10. [USACO] 奶牛混合起来 Mixed Up Cows

    题目描述 Each of Farmer John's N (4 <= N <= 16) cows has a unique serial number S_i (1 <= S_i & ...