Try   HackMD

2020q3 第 16 週測驗題

tags: sysprog2020

目的: 引導學員複習 TCP/IP 程式設計

作答表單


測驗 1

考慮到 client.cserver.c 可透過 socket 傳遞檔案,其中 client.c 程式列表如下:

/* Client code */
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define PORT_NUMBER 55555
#define SERVER_ADDRESS "localhost"
#define NEW_FILENAME "new-file.txt"
#define CHUNK_SIZE 1024

int main(int argc, char **argv)
{
    int client_socket;
    struct sockaddr_in remote_addr;
    char buffer[CHUNK_SIZE] = {0};
    long int file_size;
    int total_recv = 0;

    /* Zeroing remote_addr struct */
    memset(&remote_addr, 0, sizeof(remote_addr));

    /* Construct remote_addr struct */
    remote_addr.sin_family = AF_INET;
    remote_addr.sin_port = htons(PORT_NUMBER);
    inet_pton(AF_INET, SERVER_ADDRESS, &(remote_addr.sin_addr));

    /* Create client socket */
    client_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (client_socket < 0) {
        perror("Error creating socket");
        exit(EXIT_FAILURE);
    }

    /* Connect to the server */
    if (connect(client_socket, (struct sockaddr *) &remote_addr,
                sizeof(struct sockaddr)) < 0) {
        perror("Error connecting to server");
        exit(EXIT_FAILURE);
    }
    printf("Client connected to server at port %d\n", PORT_NUMBER);

    /* Receiving file size */
    printf("Receiving message from server.\n");
    int recv_size = recv(client_socket, buffer, sizeof(long) + 1, 0);
    file_size = atol(buffer);
    printf("\nFile size : %ld\n", file_size);

    /* Open a new file */
    FILE *fp = fopen(NEW_FILENAME, "w+");
    if (fp == NULL) {
        perror("Failed to open file");
        exit(EXIT_FAILURE);
    }

    while (total_recv < file_size) {
        recv_size = recv(client_socket, buffer, CHUNK_SIZE, 0);
        total_recv += recv_size;
        printf("Received %d Bytes. Total is %d\n", recv_size, total_recv);
        fwrite(buffer, recv_size, 1, fp);
    }
    fseek(fp, 0, SEEK_END);
    file_size = ftell(fp);
    printf("New file size: %ld\n", file_size);

    fclose(fp);
    close(client_socket);

    return 0;
}

對應的 server.c 如下:

/* Server code */
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>

#define PORT_NUMBER 55555
#define SERVER_ADDRESS "localhost"
#define FILE_TO_SEND "file.txt"
#define CHUNK_SIZE 1024

int main(int argc, char **argv)
{
    int server_socket, peer_socket;
    socklen_t sock_len;
    struct sockaddr_in server_addr, peer_addr;
    int total_read = 0;
    char buf[4096];

    memset(&server_addr, 0, sizeof(server_addr));

    server_socket = F1(AF_INET, SOCK_STREAM, 0);
    peer_socket = F2(AF_INET, SOCK_STREAM, 0);
    if (server_socket < 0 || peer_socket < 0) {
        exit(EXIT_FAILURE);
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT_NUMBER);
    inet_pton(AF_INET, SERVER_ADDRESS, &(server_addr.sin_addr));

    if ((F3(server_socket, (struct sockaddr *) &server_addr,
              sizeof(server_addr))) < 0) {
        exit(EXIT_FAILURE);
    }

    F4(server_socket, 1);

    printf("Waiting for incoming connections...\n");
    sock_len = sizeof(struct sockaddr_in);
    /* Accepting incoming peers */
    peer_socket = F5(server_socket, (struct sockaddr *) &peer_addr,
                         (socklen_t *) &sock_len);
    if (peer_socket < 0) {
        exit(EXIT_FAILURE);
    }

    /* Open file in read-only */
    FILE *fp = fopen("file.txt", "r");
    if (fp == NULL) {
        exit(EXIT_FAILURE);
    }

    fseek(fp, 0, SEEK_END);
    long int file_size = ftell(fp);
    sprintf(buf, "%ld\n", file_size);
    F6(peer_socket, buf, sizeof(long) + 1, 0);

    fseek(fp, 0, SEEK_SET);
    while (!feof(fp)) {
        int actually_read = fread(buf, 1, CHUNK_SIZE, fp);
        total_read += actually_read;

        F7(peer_socket, buf, actually_read, 0);

        int num_left = (int) file_size - total_read;
        if (num_left == 0)
            break;
    }
    fclose(fp);
    close(peer_socket);
    close(server_socket);

    return 0;
}

其中 F1 到 F7 都是 Linux 系統呼叫,請補完以符合預期。

作答區

F1 = ?

  • (a) open
  • (b) read
  • (c) write
  • (d) socket
  • (e) listen
  • (f) accept
  • (g) bind
  • (h) recv
  • (i) send

F2 = ?

  • (a) open
  • (b) read
  • (c) write
  • (d) socket
  • (e) listen
  • (f) accept
  • (g) bind
  • (h) recv
  • (i) send

F3 = ?

  • (a) open
  • (b) read
  • (c) write
  • (d) socket
  • (e) listen
  • (f) accept
  • (g) bind
  • (h) recv
  • (i) send

F4 = ?

  • (a) open
  • (b) read
  • (c) write
  • (d) socket
  • (e) listen
  • (f) accept
  • (g) bind
  • (h) recv
  • (i) send

F5 = ?

  • (a) open
  • (b) read
  • (c) write
  • (d) socket
  • (e) listen
  • (f) accept
  • (g) bind
  • (h) recv
  • (i) send

F6 = ?

  • (a) open
  • (b) read
  • (c) write
  • (d) socket
  • (e) listen
  • (f) accept
  • (g) bind
  • (h) recv
  • (i) send

F7 = ?

  • (a) open
  • (b) read
  • (c) write
  • (d) socket
  • (e) listen
  • (f) accept
  • (g) bind
  • (h) recv
  • (i) send