收发文件的服务器端/客户端实现

程序需求

  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;
}

 

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值