收發檔案的伺服器端/客戶端實現
阿新 • • 發佈:2018-11-22
程式需求
- 客戶端接受使用者輸入的傳輸檔名
- 客戶端請求伺服器端傳輸該檔名所指檔案
伺服器端程式碼:
#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; }