getfile

實現 getfile <ipaddr> <source filename> <destination filename>
例如 ./getfile 127.0.0.1 /etc/passwd passwd
顯示 成功 GET Success (12345 bytes)
失敗 Error!
參考 ch7/file
ch7/wrapper/tcputils.c



/* Server*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <string.h>
#include <stdio.h>

#include "copy.h"
#include "tcputils.h"

#define BUFFER_LENGTH   128

int main()
{
 int server_sockfd, client_sockfd;
 socklen_t client_len;
 struct sockaddr_in client_address;

    // Open a socket for the server.
    server_sockfd=open_sock(9735);

 while(1)
 {
  char buf[BUFFER_LENGTH];

  int fd;
  int size;

  printf("server waiting\n");
  /* Accept a connection. */
  client_len = sizeof(client_address);
  client_sockfd = accept(server_sockfd, (struct sockaddr *)&client_address, &client_len);

        int res;
  //  Get filename from client
  res = read(client_sockfd, buf, BUFFER_LENGTH);

  printf("Filename from client %s\n", buf);

        size = 0;
        // Open source file
        fd = open(buf,O_RDONLY);

        if (fd < 0)     // File not found
        {
            buf[0] = '0';
            write(client_sockfd, buf, 1);
        }
        else
        {
            buf[0] = '1';
            write(client_sockfd, buf, 1);

            // Start to copy file
            size = copy_file(fd,client_sockfd);


            if( size > 0 )
            {
                printf("write size = %d\n", size);
            }
            else
            {
                perror("size");
            }
        }

        close(fd);

  close(client_sockfd);
 }
}



/* Client */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>

#include "copy.h"
#include "tcputils.h"

int main(int argc, char* argv[])
{
 int sockfd;
 int fd;
 int size;
 char bResult;

    // Check parameters, I add a new parameter for destination filename.
    if (argc != 4)
    {
        printf("Usage: getfile <ipaddr> <source filename> <destination filename>\n");
        exit(EXIT_SUCCESS);
    }

 // Create a socket for the client.
 sockfd=open_clientsock(argv[1],9735);

 int res;
 // Send source filename to server
 res = write(sockfd, argv[2], strlen(argv[2])+1);

    // Get server response
    res = read(sockfd, &bResult, 1);

    if (bResult == '1')     // Server is ready to send file
    {
        size = 0;

        // Create destination file
        fd = open(argv[3],O_WRONLY|O_CREAT,0666);

        if (fd < 0)     // create file error
        {
            perror("client:");
        }

        // Copy file
        size=copy_file(sockfd,fd);

        printf("GET Success (%d bytes)\n", size);
        close(fd);
    }
    else
    {
        printf("Error!\n");
    }

 close(sockfd);
 exit(EXIT_SUCCESS);
}

程式說明如下:
  1. Server 端開啟 Socket Port 9735 後即等待 Client 端連線
  2. Client 端開啟 Socket 後請求連線
  3. Client 端先傳來源檔名給 Server 端檢查檔案是否存在
  4. Server 端若檢查成功則傳回 1,開啟來源檔案準備複製;若檢查失敗則傳回 0,結束連線
  5. Client 若收到成功訊息,則開啟目的檔案開始複製,並列印複製成功與檔案大小;若收到失敗訊息,則直接列印錯誤訊息,結束連線

執行結果如下:



注意事項:

在取得 Server 端回應時,我原本的寫法如下:

        res = read(sockfd, buf, 128);

當 Server 端傳回 "OK" 時,後續傳回來的檔案卻少了 125 Bytes。原來我在讀回應時,總共讀了 128 Bytes,其中 3 Bytes 為 "OK" 加上結束字元,而 125 Bytes 則為檔案的內容。這也驗證了老師提到處理 Buffer 要特別注意的地方,因為 Server 回應與檔案傳輸已經合併傳送了。

延伸功能:
  1. ipaddr 參數改成支援 URL
  2. 利用 fork() 支援多個檔案同時傳輸
  3. 修改為 Nonblocking I/O 的方式

留言

這個網誌中的熱門文章

Linux 批次檔的寫法

【分享】如何顯示 Debug Message

[分享] Visual Studio 遠端偵錯