我需要用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
答案 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具体实现(我猜是使用套接字)
从源
FileReader IDataSource的具体实现,用于读取磁盘上的文件以供入StreamSender
示例:
ISender sender=new StreamSender(new FileReader("filename.txt"));
sender.setDest(new StreamReceiver(host));
sender.setName(senderName);
sender.send();
显然,这只是我头脑中的一个例子。将缺少部分。