程序需求:
实现过程 服务器 一、制定UDP通信协议 设计一个UDP报头
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; }; |
|