用c ++设计文件传输协议

时间:2012-01-24 20:04:14

标签: c++ design-patterns protocols file-transfer

我需要用C ++编写一个简单的文件传输协议,以便将文件从客户端上传或下载到服务器。现在我的客户端和服务器应用程序都是do-it-all脚本。我想模块化类/方法中的所有内容,以便以后更容易修改。

要上传文件,我需要用户发送文件的名称(不进行身份验证),文件名,文件大小和文件内容。这就是我在客户端所拥有的:

int sendFile(string fileName, SOCKET s) {
    ifstream file;
    int ibytesent;
    int size;
    char fileSize[packetSize];

    // Open file, set get pointer at end of file
    file.open (fileName.c_str(), ios::binary | ios::ate);

    // Get file size and pass it to buffer
    size = (int) file.tellg();

    //itoa(size, fileSize, packetSize);
    sprintf(fileSize, "%d", size);

    // Set pointer to beginning
    file.seekg(0, ios::beg);

    // Send file size
    if (send(s, fileSize, packetSize, 0) == SOCKET_ERROR) {
        throw "Send failed\n";
    }

    cout << "Size sent: " << size;

    // Buffer the file Name
    char fileNameBuffer[packetSize];

    sprintf(fileNameBuffer, fileName.c_str());

    // Send the file name
    if (send(s, fileNameBuffer, packetSize, 0) == SOCKET_ERROR) {
        throw "Send failed\n";
    }

    cout << "File name sent: " << fileName << endl;

    char buf[packetSize];
    ibytesent = 0;
    // Loop until the whole file is sent
    while(file.good()) {
        // Read next packetSize bytes into buf
        file.read(buf, packetSize);

        // Send the read data
        ibytesent += send(s, buf, packetSize, 0);

        if (ibytessent == SOCKET_ERROR) {
            throw "Send failed\n";
        }
    }

    cout << "File sent.\n";
    //wait for reception of server response.
    ibytesrecv=0;
    /*
    if((ibytesrecv = recv(s,szbuffer,128,0)) == SOCKET_ERROR)
        throw "Receive failed\n";
    else
        cout << "File received.";
     */
    file.close();

    return 1;
}

然后有一个main()方法打开一个套接字并连接到服务器。我的问题是关于如何设计/实现适当的文件传输协议。什么是良好的结构呢?我还想知道您对如何将文件拆分(和发送)到数据包结构而不是我现在的方式的意见。我不一定需要代码,而是将关注点分离到这个和那个类等等。

请不要推荐已有的协议,因为这不是本练习的重点。

由于

编辑我发现了类似于我在这里寻找的东西:http://www.eventhelix.com/realtimemantra/PatternCatalog/protocol_layer.htm

2 个答案:

答案 0 :(得分:3)

(我认为这就是你所要求的)

一个简单的协议可以在文件内容之前加上一个 name = value 对列表,这些对定义了正在发送的文件的属性,空 name = value 对终止列表。 name = value 对由换行符终止。

例如:

sending-user-name=userA\n
file-name=filea.txt\n
is-binary=false\n
byte-count=442\n\n
<file-content-here>

sending-user-name=userZ\n
file-name=filez.zip\n
is-binary=true\n
byte-count=1087\n\n
<file-content-here>

服务器代码将处理属性,并且能够以正确模式打开文件(二进制或不二进制),并且确切地知道它必须读取多少字节。

Narrakan评论查看非阻塞套接字和select(),您可以使用它来确定套接字何时可重新编辑或可写入。

答案 1 :(得分:1)

以下是您可能的课程:

  • 发送者和接收者的ISender和IReceiver接口

  • 分别使用iSender和IReceiver的StreamSender和StreamReceiver具体实现(我猜是使用套接字)

  • 从源

  • 获取数据的IDataSource接口
  • FileReader IDataSource的具体实现,用于读取磁盘上的文件以供入StreamSender

示例:

ISender sender=new StreamSender(new FileReader("filename.txt"));
sender.setDest(new StreamReceiver(host));
sender.setName(senderName);
sender.send();

显然,这只是我头脑中的一个例子。将缺少部分。