一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - C/C++ - Linux網(wǎng)絡(luò)編程之基于UDP實(shí)現(xiàn)可靠的文件傳輸示例

Linux網(wǎng)絡(luò)編程之基于UDP實(shí)現(xiàn)可靠的文件傳輸示例

2021-01-28 15:03C語(yǔ)言程序設(shè)計(jì) C/C++

這篇文章主要介紹了Linux網(wǎng)絡(luò)編程之基于UDP實(shí)現(xiàn)可靠的文件傳輸示例,是很實(shí)用的技巧,需要的朋友可以參考下

了解網(wǎng)絡(luò)傳輸協(xié)議的人都知道,采用TCP實(shí)現(xiàn)文件傳輸很簡(jiǎn)單。相對(duì)于TCP,由于UDP是面向無(wú)連接、不可靠的傳輸協(xié)議,所以我們需要考慮丟包和后發(fā)先至(包的順序)的問(wèn)題,所以我們想要實(shí)現(xiàn)UDP傳輸文件,則需要解決這兩個(gè)問(wèn)題。方法就是給數(shù)據(jù)包編號(hào),按照包的順序接收并存儲(chǔ),接收端接收到數(shù)據(jù)包后發(fā)送確認(rèn)信息給發(fā)送端,發(fā)送端接收確認(rèn)數(shù)據(jù)以后再繼續(xù)發(fā)送下一個(gè)包,如果接收端收到的數(shù)據(jù)包的編號(hào)不是期望的編號(hào),則要求發(fā)送端重新發(fā)送。

下面展示的是基于linux下C語(yǔ)言實(shí)現(xiàn)的一個(gè)示例程序,該程序定義一個(gè)包的結(jié)構(gòu)體,其中包含數(shù)據(jù)和包頭,包頭里包含有包的編號(hào)和數(shù)據(jù)大小,經(jīng)過(guò)測(cè)試后,該程序可以成功傳輸一個(gè)視頻文件。

具體實(shí)現(xiàn)代碼如下:

server端代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*************************************************************************
  > File Name: server.c
  > Author: SongLee
 ************************************************************************/
#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()
{
  /* 發(fā)送id */
  int send_id = 0;
 
  /* 接收id */
  int receive_id = 0;
 
  /* 創(chuàng)建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);
 
  /* 創(chuàng)建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);
  }
 
  /* 數(shù)據(jù)傳輸 */
  while(1)
  {  
    /* 定義一個(gè)地址,用于捕獲客戶端地址 */
    struct sockaddr_in client_addr;
    socklen_t client_addr_length = sizeof(client_addr);
 
    /* 接收數(shù)據(jù) */
    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);
 
    /* 打開(kāi)文件 */
    FILE *fp = fopen(file_name, "r");
    if(NULL == fp)
    {
      printf("File:%s Not Found.\n", file_name);
    }
    else
    {
      int len = 0;
      /* 每讀取一段數(shù)據(jù),便將其發(fā)給客戶端 */
      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; /* 發(fā)送id放進(jìn)包頭,用于標(biāo)記順序 */
            data.head.buf_size = len; /* 記錄數(shù)據(jù)長(zhǎng)度 */
            if(sendto(server_socket_fd, (char*)&data, sizeof(data), 0, (struct sockaddr*)&client_addr, client_addr_length) < 0)
            {
              perror("Send File Failed:");
              break;
            }
            /* 接收確認(rèn)消息 */
            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和發(fā)送的id不相同,重新發(fā)送 */
          if(sendto(server_socket_fd, (char*)&data, sizeof(data), 0, (struct sockaddr*)&client_addr, client_addr_length) < 0)
          {
            perror("Send File Failed:");
            break;
          }
          /* 接收確認(rèn)消息 */
          recvfrom(server_socket_fd, (char*)&pack_info, sizeof(pack_info), 0, (struct sockaddr*)&client_addr, &client_addr_length);
          receive_id = pack_info.id; 
        }
      }
      /* 關(guān)閉文件 */
      fclose(fp);
      printf("File:%s Transfer Successful!\n", file_name);
    }
  }
  close(server_socket_fd);
  return 0;
}

client端代碼如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*************************************************************************
  > File Name: client.c
  > Author: SongLee
 ************************************************************************/
#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;
 
  /* 服務(wù)端地址 */
  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);
 
  /* 創(chuàng)建socket */
  int client_socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
  if(client_socket_fd < 0)
  {
    perror("Create Socket Failed:");
    exit(1);
  }
 
  /* 輸入文件名到緩沖區(qū) */
  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));
 
  /* 發(fā)送文件名 */
  if(sendto(client_socket_fd, buffer, BUFFER_SIZE,0,(struct sockaddr*)&server_addr,server_addr_length) < 0)
  {
    perror("Send File Name Failed:");
    exit(1);
  }
 
  /* 打開(kāi)文件,準(zhǔn)備寫入 */
  FILE *fp = fopen(file_name, "w");
  if(NULL == fp)
  {
    printf("File:\t%s Can Not Open To Write\n", file_name); 
    exit(1);
  }
 
  /* 從服務(wù)器接收數(shù)據(jù),并寫入文件 */
  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;
        /* 發(fā)送數(shù)據(jù)包確認(rèn)信息 */
        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) /* 如果是重發(fā)的包 */
      {
        pack_info.id = data.head.id;
        pack_info.buf_size = data.head.buf_size;
        /* 重發(fā)數(shù)據(jù)包確認(rèn)信息 */
        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;
}

感興趣的朋友可以動(dòng)手測(cè)試一下該程序,相信會(huì)對(duì)大家的Linux下C語(yǔ)言網(wǎng)絡(luò)編程帶來(lái)一定的幫助。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 好大好硬好深好爽想要小雪 | 四虎色影院 | 97porm自拍视频区原创 | 大伊香蕉精品视频一区 | 天天色综合久久 | 美女插插视频 | 亚洲福利天堂 | 美国玩尿眼道videos | 好大好爽好舒服视频 | 亚洲成人中文 | 成人无高清96免费 | 4438成人网| 精品一区二区三区视频日产 | 四虎影院在线免费观看视频 | 美女脱了内裤打开腿让人羞羞软件 | 日本不卡在线观看免费v | 青青青国产在线观看 | 动漫美女强行被吸乳做羞羞事 | 欧美黑人成人免费全部 | 成成人看片在线 | 俄罗斯一级淫片 | 色综合色综合 | 3d动漫美女被吸乳羞羞视频 | 青青草精品在线 | 古代翁熄乩伦小说h | 亚洲国产第一区二区香蕉日日 | 亚洲免费在线观看 | 久久三级视频 | 成年人免费观看的视频 | 二次元美女脱裤子让男人桶爽 | 青青青手机视频 | 欧美亚洲天堂 | www.精品视频| 欧美日韩国产手机在线观看视频 | porno movie hd高清| 欧美一卡2卡3卡四卡海外精品 | 色综七七久久成人影 | 日本天堂视频在线观看 | 国产成人精品免费大全 | 97se狠狠狠狠狼亚洲综合网 | 国产精品手机视频一区二区 |