📜  使用UDP进行文件传输的C程序(1)

📅  最后修改于: 2023-12-03 15:36:37.568000             🧑  作者: Mango

使用UDP进行文件传输的C程序

本程序使用UDP协议进行文件传输。UDP协议通常用于需要较少或没有错误检测和重发机制的应用程序中,如视频流传输、音频流传输等。

实现步骤
  1. 创建UDP socket。
int sockfd;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
    perror("socket creating");
    exit(EXIT_FAILURE);
}
  1. 绑定socket。
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
    perror("bind server socket");
    exit(EXIT_FAILURE);
}
  1. 接收客户端请求,打开要传输的文件。
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
char filename[MAX_FILENAME_LENGTH];
int filename_len;
size_t file_size;
int current_size;

// receive file request from client
filename_len = recvfrom(sockfd, filename, MAX_FILENAME_LENGTH, 0, (struct sockaddr*)&client_addr, &client_addr_len);
if (filename_len < 0) {
    perror("filename receive");
    exit(EXIT_FAILURE);
}

// open file for reading
FILE* fp = fopen(filename, "rb");
if (!fp) {
    perror("file open");
    exit(EXIT_FAILURE);
}

// get file size
fseek(fp, 0L, SEEK_END);
file_size = ftell(fp);
rewind(fp);
  1. 发送文件大小。
// send file size to client
if (sendto(sockfd, &file_size, sizeof(file_size), 0, (struct sockaddr*)&client_addr, client_addr_len) < 0) {
    perror("file size send");
    exit(EXIT_FAILURE);
}
  1. 循环读取文件,每次读取一定大小的数据并发送给客户端。
int buffer_size = MIN(BUFFER_SIZE, file_size - current_size);
char buffer[buffer_size];
while (current_size < file_size) {
    // read data from file
    int bytes_read = fread(buffer, sizeof(char), buffer_size, fp);
    if (bytes_read < 0) {
        perror("file read");
        exit(EXIT_FAILURE);
    }
    current_size += bytes_read;

    // send data to client
    if (sendto(sockfd, buffer, bytes_read, 0, (struct sockaddr*)&client_addr, client_addr_len) < 0) {
        perror("file send");
        exit(EXIT_FAILURE);
    }

    // update buffer size if necessary
    buffer_size = MIN(BUFFER_SIZE, file_size - current_size);
}
  1. 关闭文件和socket。
fclose(fp);
close(sockfd);
参考代码

完整的程序代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 12345
#define MAX_FILENAME_LENGTH 256
#define BUFFER_SIZE 4096

#define MIN(a, b) ((a) < (b) ? (a) : (b))

int main(int argc, char** argv) {
    int sockfd;
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0) {
        perror("socket creating");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    if (bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
        perror("bind server socket");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    char filename[MAX_FILENAME_LENGTH];
    int filename_len;
    size_t file_size;
    int current_size;

    // receive file request from client
    filename_len = recvfrom(sockfd, filename, MAX_FILENAME_LENGTH, 0, (struct sockaddr*)&client_addr, &client_addr_len);
    if (filename_len < 0) {
        perror("filename receive");
        exit(EXIT_FAILURE);
    }

    // open file for reading
    FILE* fp = fopen(filename, "rb");
    if (!fp) {
        perror("file open");
        exit(EXIT_FAILURE);
    }

    // get file size
    fseek(fp, 0L, SEEK_END);
    file_size = ftell(fp);
    rewind(fp);

    // send file size to client
    if (sendto(sockfd, &file_size, sizeof(file_size), 0, (struct sockaddr*)&client_addr, client_addr_len) < 0) {
        perror("file size send");
        exit(EXIT_FAILURE);
    }

    // read and send file contents to client
    int buffer_size = MIN(BUFFER_SIZE, file_size - current_size);
    char buffer[buffer_size];
    while (current_size < file_size) {
        // read data from file
        int bytes_read = fread(buffer, sizeof(char), buffer_size, fp);
        if (bytes_read < 0) {
            perror("file read");
            exit(EXIT_FAILURE);
        }
        current_size += bytes_read;

        // send data to client
        if (sendto(sockfd, buffer, bytes_read, 0, (struct sockaddr*)&client_addr, client_addr_len) < 0) {
            perror("file send");
            exit(EXIT_FAILURE);
        }

        // update buffer size if necessary
        buffer_size = MIN(BUFFER_SIZE, file_size - current_size);
    }

    fclose(fp);
    close(sockfd);

    return 0;
}