socket通信 UDP文件傳輸(多客戶端)——附源碼

程序需求:

  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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章