1. 程式人生 > >收發檔案的伺服器端/客戶端實現

收發檔案的伺服器端/客戶端實現

程式需求

  1. 客戶端接受使用者輸入的傳輸檔名
  2. 客戶端請求伺服器端傳輸該檔名所指檔案

伺服器端程式碼:

#include <iostream>
#include <string>
 
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
 
const int bufSize = 1024;
 
void error_handling(const std::string &message);
 
int main(int argc, char *argv[])
{
    int serv_sock, clnt_sock;
    char buffer[bufSize];
    int str_len, i;
 
    struct sockaddr_in serv_addr, clnt_addr;
    socklen_t clnt_addr_sz;
 
    if(argc != 2) {
        std::cout << "Usage : " << argv[0] << " <port>" << std::endl;
        exit(1);
    }
 
    serv_sock = socket(PF_INET, SOCK_STREAM, 0);
    if(serv_sock == -1)
        error_handling("socket() error");
 
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    serv_addr.sin_port = htons(atoi(argv[1]));
 
    if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) == -1)
        error_handling("bind() error");
 
    if(listen(serv_sock, 1) == -1)
        error_handling("listen() error");
 
    clnt_addr_sz = sizeof(clnt_addr);
 
    for(size_t cnt = 0; true; ++cnt) {
        // get client socket
        clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_addr, &clnt_addr_sz);
        if(clnt_sock == -1)
            error_handling("accept() error");
        std::cout << "Client connected, seq:" << cnt << std::endl;
 
        // get the filename
        memset(buffer, 0, bufSize);
        if((recv(clnt_sock, buffer, bufSize, 0)) < 0) {
            error_handling("failed to filename data!");
            break;
        }
 
        // start transmission
        std::string filename(buffer);
        FILE *fp = fopen(filename.c_str(), "r");
        if(fp == NULL) 
            std::cout << "NO_SUCH_FILE_REQUEST" << std::endl;
        else {
            memset(buffer, 0, bufSize);
            int sd_sz;  // size of data to send
            while((sd_sz = fread(buffer, 1, bufSize, fp)) > 0) {
                if(send(clnt_sock, buffer, sd_sz, 0) < 0) {  // see if failed
                    std::cout << "SEND_FILD_FAILED" << std::endl;
                    break;
                }
                memset(buffer, 0, bufSize);           
            }
            fclose(fp);
        }
 
        close(clnt_sock);
        std::cout << "clnt_sock closed (seq:" << cnt << ")" << std::endl;
    }
 
    close(serv_sock);
    return 0;
}
 
void error_handling(const std::string &message) {
    std::cerr << message << std::endl;
    exit(1);
}

客戶端程式碼:

#include <iostream>
#include <string>
#include <regex>
 
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
 
const int bufSize = 1024;
void error_handling(const std::string &message);
int filename_check(const std::string &filename);
 
int main(int argc, char *argv[]) {
    int sock;
    char buffer[bufSize];
    std::string str_msg;
    int str_len;
    struct sockaddr_in serv_addr;
 
    if(argc != 3) {
        std::cout << "usage : " << argv[0] << " <IP> <port>" << std::endl;
        exit(1);
    }
    
    sock = socket(PF_INET, SOCK_STREAM, 0);
    if(sock == -1)
        error_handling("socket() error");
 
    memset(&serv_addr, 0, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr = inet_addr(argv[1]);
    serv_addr.sin_port = htons(atoi(argv[2]));
 
    if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1)
        error_handling("connect() error!");
    std::cout << "Connected......" << std::endl;
    std::cout << "Use 'quit' to finish the download" << std::endl;
 
    // get filename
    std::cout << "Input filename: " << std::ends;
    getline(std::cin, str_msg);
    // ATTENTION: these check should have been implemented in the server
    if(filename_check(str_msg) != 0)
        return 0;
 
    // check 
    FILE *fp = fopen(str_msg.c_str(), "w");
    if (fp == NULL)
        error_handling("Can't open/create the file!");
 
    if((send(sock, str_msg.c_str(),  str_msg.length(), 0)) < 0)
        error_handling("Send filename failed");
    std::cout << "filename sent..." << std::endl;
 
    int recv_sz;
    while( (recv_sz = recv(sock, buffer, bufSize-1, 0)) > 0 ) {    // receive the data
        if(fwrite(buffer, recv_sz, 1, fp) < 0) {    // write to a file
            std::cout << "Failed to write the file!" << std::endl;
            break;
        }
        memset(buffer, 0, bufSize);
    }
    std::cout << "Download finished..." << std::endl;
    fclose(fp);
    close(sock);
    return 0;
}
 
void error_handling(const std::string &message) {
    std::cerr << message << std::endl;
    exit(1);
}
 
int filename_check(const std::string &filename) {
    // check quit
    if(std::regex_match(filename, std::regex("[Qq]uit"))) {
        std::cout << "Client closed....." << std::endl;
        return 1;
    }
    // check illegal filename
    if(std::regex_match(filename, std::regex(".*(([\\.]{2})|([/])).*"))) {
        std::cout << "illegal filename!" << std::endl;
        return 2;
    }
    return 0;
}