C++中TCP通信實現文件傳輸


作為Computer networks課程的一個project,我們需要實現用TCP在mininet中client和server的相互通信,需要能夠傳輸文本文件,binary file 和image file。整個project的目的還是比較明確的。我主要列出了一下幾個問題,需要在代碼中實現。

1. 實現main函數的接口

因為client和server 需要的參數需要通過命令行輸入,所以需要用getoptlong函數來實現。

int main(int argc, char* argv[])
{
    int code;
    int flag;
    int server_port;
    int client_port;
    string hostname;
    string filename;
    while(1)
    {
      static struct option long_options[]={
           {"c", no_argument, &flag, 1},
            {"s", no_argument, &flag, 0},
            {"port", required_argument, 0, 'p'},
            {"host", required_argument, 0, 'h'},
            {"file", required_argument, 0, 'f'},
            {"sp", required_argument, 0, 'e'},
            {"cp", required_argument, 0, 'l'}
      };
      int option_index=0;
       code=getopt_long_only(argc,argv,"p:h:f:e:l:", long_options, &option_index);
       if(code==-1) break;
       switch(code)
       {
           case 'p': server_port=atoi(optarg); break;
            case 'h': hostname=string(optarg); break;
            case 'f': filename=string(optarg); break;
            case 'e': server_port=atoi(optarg);break;
            case 'l': client_port=atoi(optarg);break;
          default: break;
       }
    }
    if(flag)
        send_message(hostname.c_str(), server_port, filename.c_str(), client_port);
    else 
        run_server(server_port); 

 

2. 實現socket programming中的功能

在這個項目中提供了UDP的socket programming的接口,按照需要設置即可。

   // (1) Create a socket
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); //hzd: socket interface structure

    // (2) Create a sockaddr_in to specify remote host and port
    struct sockaddr_in server_addr; // specify server's address
    server_addr.sin_family = AF_INET;

    // Step (2): specify socket address (hostname).
    // The socket will be a client, so call this unix helper function to convert a hostname string to a useable `hostent` struct.
    // hostname here may be 10.0.0.1
    struct hostent *host = gethostbyname(hostname); //hzd: instantiate a instance of host with name specified
    if (host == nullptr) {
        fprintf(stderr, "%s: unknown host\n", hostname);
        return -1;
    }
    memcpy(&(server_addr.sin_addr), host->h_addr, host->h_length);//hzd: copy the hostname to the server address

    // if we also we also want to bind client's socket to a port number...
    struct sockaddr_in my_addr;//hzd: the address of the client
    memset(&my_addr, 0, sizeof(my_addr));//hzd: alloctae memory for the my_addr.
    my_addr.sin_family = AF_INET;
    my_addr.sin_addr.s_addr = INADDR_ANY; //INADDRY_ANY == 0.0.0.0
    my_addr.sin_port = htons(client_port); //hzd: specify the port number of the client
    bind(sockfd, (struct sockaddr *) & my_addr, sizeof(my_addr));// hzd: bind the address of client to the socket


    // Step (3): Set the port value.
    // Use htons to convert from local byte order to network byte order.
    server_addr.sin_port = htons(port);//hzd: spcify the port of sever


    // (3) Connect to remote server
    if (connect(sockfd, (sockaddr *) &server_addr, sizeof(server_addr)) == -1) {
        perror("Error connecting stream socket");
        return -1;
    }
 

 

3. 連續send造成的粘包問題

由於TCP擁有優化算法,可以將多個send的數據被一個recv收到,所以造成粘包問題。本項目中會要求先發送文件長度,再發送文件,連續發送造成文件長度和文件粘合在一起,造成無法讀出文件。解決辦法是加入sleep()函數在兩次send之間。這樣就能將兩次send分開了。

 

4. 大文件的接收問題

大文件的接受容易由於buffer長度的限制,造成丟失。因此需要設置一個MAX_MESSAGE_SIZE。分成多次完成接收。本來想要在send端也多次發送,效果不好。

5. 文件的讀寫

由於文件的類型不確定,打開文件都需要用binary格式,讀寫的時候一定要注意,用read()和write()函數,千萬不要<<或者>>,因為后一種方式沒法確定文件類型。

ifstream infile;
infile.open((const char*) msg,ios::in|ios::binary);
char* data;
infile.seekg(0, ios::end);
int length=infile.tellg();
infile.seekg(0, ios::beg);
data= new char[length];
infile.read(data,length);

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM