分享

socket通信 UDP文件传输(多客户端)

 barry525 2015-03-03

程序需求:

  1. 程序分为server程序和client程序,通讯由client主动发起请求一个指定的文件,由server传文件给client。
  2.  一个server可以支持多个client通信。
  3. 数据包要有校验机制。
  4. 有丢包重传机制。
  5. 支持断点续传。
  6. 能正常处理各种异常现象。

实现过程

      服务器

       一、制定UDP通信协议

               设计一个UDP报头

              type
               len
                id   
            check
              data

1、type(数据类型):char

          给出这个UDP包的数据类型及服务器的处理方式。我现在把它分为不同的几个值:文件传输申请,客户端收到一个数据包后的确认(重传、继续)

   断点续传(掉线后重新建立连接并接着以前的传输),文件件传输结束(服务器到客户端),文件传输错误,等。

2、len(数据包长度):int

3、check(校验和):int

           对包进行CRC校验和,防止数据传输过程中错误。

4、id(标识):long int

          对文件传输时对数据包进行标号,在断点续传时标识文件断点位置,等(根据type需求改变)


   二、服务器事件处理机制

                 一开始我准备使用一个链表来接收保存客户端的请求、再用一个链表队列来处理相应的请求(另一个处理线程)、还有一个超时处理队列。最后发现变得很复杂(对链表操作不是很熟练)。决定只用一个全局数组来代替上面三个链表的功能。

              开两个线程一个用于循环接收客户端发来的数据,并进行分类标记放入数组中,另一个线程用于处理数组中待处理的事件。(一个客户端一个数组元素)

              每个客户端分配一个结构体并放入数组中。

              客户 结构体:flag (标识)、clinet_addr(客户端地址)、timer(时间)、struct   file_info(文件信息)、等

                  flag:标记客户端状态(等待传输、服务器等待反映、已经超时、空客户端等)            

                  timer:记录客户端最后反映的时刻、用于判断超时。

                  file_info:(文件路径,文件指针,文件偏移量)记录文件传输情况。

          

        主线程中循环判断是否有客户端连接超时。


   客户端

       向服务器申请文件(先判断是否断点),当断点重传时,用fseek函数找到断点,并把断点信息发给服务器端,服务器重断点处重新读取文件开始传输。发出请求后等待服务器答复,服务器答复后开始计数接受文件包。服务器给每个包编上编号,客户端每接收一个udp包放到缓冲区中,当缓冲区慢后就按包编号顺序写到文件中记录编号。当没有要写的编号时,给服务器发送重发这个包ACK。


头文件

#include <sys/socket.h>
#include <string.h>
#include <netinet/in.h>
#include <stdio.h>
#include <fcntl.h>
#include <time.h>
#include <strings.h> 
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>


/*udp_datapack->type*/
#define REQ_FILE 0
#define ACK_TRUE 1
#define ACK_FAIL 2
#define ACK_RECONNECT   3
#define FILE_DATE 4




/*udp_req->flag udp类型*/
#define CLINET_EMPTY 0
#define CLINET_FIRST_REQ 1
#define CLINET_TIME_OUT 2
#define CLINET_LINK_ACK_WAIT 3
#define CLINET_LINK_ACK_TRUE 4
#define CLINET_LINK_ACK_FAIL    5


/*send_ack flag. 当udp为ACK时 udp头中label的值*/
/*udp_datapack->type=ACK_TRUE | ACK_FAIL ===> udp_datapack->label  */
#define SERVER_CLINET_FULL      0
#define FIND_FILE 1
#define UNFIND_FILE 2
#define FILE_OVER 3
#define TYPE_UNRECOGNIZED 4
#define CRC_FAIL 5
#define FILE_READ_FAIL 6


/*clinet file flag(file_pack_num) */
#define FILE_COMPLETE -1
#define FILE_INCOMPLETE -2
#define SERVER_BUSY -3
#define FILE_NOT_EXIST -4
#define FILE_SERV_READ_FAIL -5
#define RE_APPLY -6


#define SERV_PORT 8888  /*端口号*/
#define MAX       1024     /*udp数据部分大小*/
#define MAX_UDP_CLINET 10  /*服务器处理客户端最大量*/

#define UDP_HEAD_LEN 13 /*udp头大小*/

#define TIMEVAL      45 /*超时时间*/


/*udp包格式定义*/
struct udp_datapack{
char type; /*数据包类型*/
long int label; /*文件包号、请求包文件位置信息*/
int size; /*包大小*/
int check; /*CRC*/
char data[MAX];
};




/*传输的文件信息*/
struct file_infor{
char *file_path;
FILE * file_fp;
off_t  seek_flag;  
};


/*服务器保存的客户端信息*/
struct udp_req{
char flag; /*客户端状态*/
int   fsend_label; /*跟据flag变化*/
struct sockaddr_in  req_addr; /*客户端地址*/
struct file_infor  req_file; /*客户所请求的文件信息*/
struct timeval      timeout; /*超时计时*/
};


/*本地socket信息*/
struct local_infor{
int sockfd;
struct sockaddr_in local_addr;
};


完整源码下载地址:http://download.csdn.net/user/jmq_0000

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多