簡體   English   中英

UDP套接字:服務器將文件發送到客戶端地址家族,而協議家族不支持

[英]UDP socket: server sending file to client Address family not supported by protocol family

我只是套接字編程的初學者,目前正在研究一個使用UDP處理文件傳輸的小程序。 該程序用C語言編寫。

這是我的問題:
UDP服務器將首先使用recvfrom()函數捕獲來自UDP客戶端的消息,以便開始發送文件。 我先發送了文件名,但它無法通過,顯示為: 協議族不支持的地址族作為錯誤message()。 我檢查了client_addr的sin_family,它是7。此外,在嘗試設置client_addr.sin_family = AF_INET之后 服務器工作正常,除了客戶端什至沒有收到任何消息。

我已經檢查了一些資料,但是它並沒有那么有用,請問是否有人知道為什么並且願意告訴。 感謝您的幫助。

以下是服務器代碼的一小部分:

int socketfd;
/* my address information */
struct sockaddr_in server_addr;
/* connector’s address information */
struct sockaddr_in client_addr;
socklen_t clientLength;
int numbytes;
char buffer[BUFLEN];
int portNum = atoi(port);
time_t timer;
char charfileSize[20];
int percent, count = 0;
struct tm *tm_info;
char timeBuf[30];
if((socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
  perror("Server-socket() sockfd error lol!");
  exit(1);
} else {
  printf("Server-socket() sockfd is OK...\n");
}

server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(portNum);
server_addr.sin_addr.s_addr = INADDR_ANY;
memset(&(server_addr.sin_zero), 0, 8);

// bind the socket to the server ip address
if(bind(socketfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) {
  perror("server socket bind to IP error lol!\n");
  exit(1);
} else {
  printf("successfully bind server ip with socket ...\n");
}
// client_addr.sin_port = htons(portNum);
client_addr.sin_family = AF_INET;

//*  for ensuring client connection  *//
int tempGet;
char tempBuf[BUFLEN];
//if( (tempGet = recvfrom(socketfd, tempBuf, BUFLEN, 0, (struct sockaddr *)&client_addr, &clientLength)) > 0 ) {
tempGet = recvfrom(socketfd, tempBuf, BUFLEN, 0, (struct sockaddr *)&client_addr, &clientLength);
if( strcmp( tempBuf, "send file" ) == 0) {
  printf("Can start transferring file...\n");
}
printf("sin family:%d\n", client_addr.sin_family);

FILE *fp = fopen(filename, "rb");
if ( !fp ) {
  perror("Error opening the file\n");
  exit(1);
} else {
  // successfully opened the file that's going to be transferred
  printf("file opened: %s\n", filename);

  // get file size
  int file_block_size = 0;
  bzero(buffer, BUFLEN);
  long file_size;
  fseek(fp, 0, SEEK_END);
  file_size = ftell(fp);
  // goes back to the beginning of file(fp)
  rewind(fp);
  printf("file name: %s\n", filename);
  printf("file size: %ld kb\n", file_size/1024);
  // get time
  time(&timer);
  clientLength = sizeof(client_addr);

  //client_addr.sin_family = AF_INET;
  int sendFileName;
  // length of file name
  if( (sendFileName = sendto(socketfd, filename, strlen(filename), 0, (struct sockaddr *)&client_addr, sizeof(struct sockaddr_in))) >= 0) {
    printf("file name sent.\n");
  } else {
    //printf("%d\n", sendFileName);
    perror("file name send error.\n");
    exit(1);
  }
}

recvfrom的最后一個參數采用socklen_t的地址,該地址需要使用sockaddr參數的大小進行初始化。 我沒有在此調用之前初始化clientLength ,因此當該函數返回時, client_addr可能未正確更新。 這將導致隨后的發送到sendto調用失敗。

如果在調用recvfrom之前初始化clientLength ,將會解決該問題。

clientLength = sizeof(client_addr);
tempGet = recvfrom(socketfd, tempBuf, BUFLEN, 0, (struct sockaddr *)&client_addr, &clientLength);

我對堆棧溢出中所有不正確和半正確的UDP套接字程序嘗試感到有些厭倦。 我已決定以這個問題為例,進行參考UDP實現。 下次我看到TCP問題(並花費一些時間和精力)時,將參考TCP實現。

此實現正確完成了所有操作(據我所知:)。 它使用BSD套接字,因此Windows實現將必須進行較小的更改。 除此之外,它應該全部是C-99。

錯誤處理:應用程序檢查可能的錯誤,但不嘗試糾正錯誤,僅報告即可。 還已知在某些錯誤情況下會導致套接字泄漏(這會導致應用程序關閉),但是在這種情況下添加適當的套接字關閉將僅保證提供更多代碼,而沒有實際增加很多好處。

匯編:

gcc -std=c99 -g -D_POSIX_SOURCE -Wall -Werror -pedantic -o test_udp send_udp.c

用法: ./test_udp服務器./test_udp <主機名> <文件名>

看哪:我給你test_udp.c

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

const short port = 4321;

int run_server();
int send_file(const char* const server, const char* const file);

int main(int argc, char* argv[]) {
    if (argc < 2 || argc > 3) {
        printf("Error: Usage send_udp (server|<server_host>) [<file name>]\n");
        return 1;
    }

    if (!strcmp(argv[1], "server"))
        return run_server(); // runs forever

    if (argc != 3) {
        printf("Error: client mode accepts two arguments: server and file name.\n");
        return 1;
    }

    return send_file(argv[1], argv[2]);
}

int run_server() {
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock == -1) {
        printf("run_server(): error creating socket: %s\n", strerror(errno));
        return 2;
    }

    struct sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(sock, (struct sockaddr*)&addr, sizeof(addr))) {
        printf("run_server(): error binding socket: %s\n", strerror(errno));
        return 2;
    }
    printf("run_server(): socket created and bound, entering endless loop.\n");

    struct sockaddr_in incoming;
    socklen_t incoming_sz = sizeof(incoming);
    char buff[USHRT_MAX]; // maximum size of UDP datagramm
    const char* buff_ptr = buff;
    while (1) {
        ssize_t msg_size = recvfrom(sock, buff, sizeof(buff), 0, (struct sockaddr*)(&incoming), &incoming_sz);
        if (msg_size == -1) {
            printf("run_server(): error receiving message: %s\n", strerror(errno));
            return 3;
        }

        if (msg_size == 0) {
            printf("run_server(): a message of 0 size received from the client, bogus. Skipping, continue to listen.\n");
            continue;
        }

        // Message structure: unsigned 16 bit length of file name (network order), followed by filename, followed by data
        uint16_t fname_len;
        if (msg_size < sizeof(fname_len)) {
            printf("run_server(): Bogus (too short) message received from the client. Skipping, continue to listen.\n");
            continue;
        }

        memcpy(&fname_len, buff_ptr, sizeof(fname_len));
        fname_len = ntohs(fname_len);
        buff_ptr += sizeof(fname_len);
        msg_size -= sizeof(fname_len);
        if (msg_size < fname_len) {
            printf("run_server(): Bogus (too short) message received from the client. Skipping, continue to listen.\n");
            continue;
        }

        char file_name[fname_len + 1];
        strncpy(file_name, buff_ptr, fname_len);
        file_name[fname_len] = '\0';
        buff_ptr += fname_len;
        msg_size -= fname_len;
        printf("run_server(): incoming transfer for file %s, intrinsic file size: %zu\n", file_name, msg_size);

        FILE* f = fopen(file_name, "wb");
        if (!f) {
            printf("run_server(): Could not open file for writing. Skipping the message, carrying on.\n");
            continue;
        }

        size_t written = fwrite(buff_ptr, msg_size, 1, f);
        if (written != 1)
            printf("run_server(): error, could not write whole file.\n");
        else
            printf("run_server(): incoming file written successfully.\n");

        fclose(f);
    }

    return 0;
}

int send_file(const char* const server, const char* const file) {
    uint16_t fname_len = strlen(file);
    uint16_t max_short = 0;
    max_short = ~max_short;
    if (fname_len > (max_short - sizeof(fname_len))) {
        printf("send_file(): file name is toooo large. Can't send this file.\n");
        return 2;
    }
    FILE* f = fopen(file, "rb");
    if (!f) {
        printf("send_file(): Could not open file for reading. Nothing sent.\n");
        return 3;
    }
    fseek(f, 0, SEEK_END);
    unsigned long fsize = ftell(f);
    fseek(f, 0, SEEK_SET);
    if (fsize > max_short - sizeof(fname_len) - fname_len) {
        printf("send_file(): file is toooo large. Can't send this file.\n");
        fclose(f);
        return 2;
    }

    char buff[sizeof(fname_len) + fname_len + fsize];
    char* buff_ptr = buff;
    uint16_t net_fname_len = htons(fname_len);
    memcpy(buff_ptr, &net_fname_len, sizeof(net_fname_len));
    buff_ptr += sizeof(net_fname_len);
    memcpy(buff_ptr, file, fname_len);
    buff_ptr += fname_len;

    size_t rc = fread(buff_ptr, fsize, 1, f);
    if (rc != 1) {
        printf("send_file(): Could not read whole file. Error.\n");
        fclose(f);
        return 3;
    }
    fclose(f);

    struct addrinfo* ainfo;
    if (getaddrinfo(server, NULL, NULL, &ainfo) != 0) {
        printf("send_file(): Unknown host %s.\n", server);
        return 3;
    }
    struct addrinfo* ainfo_begin = ainfo;

    // I will take the first IP v4 entry in possible addressess
    while (ainfo->ai_family != AF_INET && ainfo->ai_next)
        ainfo = ainfo->ai_next;

    if (ainfo->ai_family != AF_INET) {
        printf("send_file(): Couldn't resolve host %s to AF_INET address.\n", server);
        return 3;
    }

    int addr = ((struct sockaddr_in*)(ainfo->ai_addr))->sin_addr.s_addr;
    freeaddrinfo(ainfo_begin);

    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock == -1) {
        printf("read_file(): error creating socket: %s\n", strerror(errno));
        return 2;
    }

    struct sockaddr_in remote_addr;
    remote_addr.sin_family = AF_INET;
    remote_addr.sin_port = htons(port);
    remote_addr.sin_addr.s_addr = addr;

    ssize_t sent = sendto(sock, buff, sizeof(buff), 0, (struct sockaddr*)(&remote_addr), sizeof(remote_addr));
    if (sent != sizeof(buff))
        printf("read_file(): error sending message over socket: %s, only %zu bytes sent.\n", strerror(errno), sent);
    else
        printf("read_file(): file sent successfully.\n");

    return sent == sizeof(buff) ? 0 : 3;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM