我正在使用一台内存有限的小型嵌入式设备,并需要从该设备向服务器发送大文件。因此,我不能轻易地使用要求我在发送前将整个文件加载到内存中的HTTP POST。
不,POST并不要求如此。它所要求的只是您发送的HTTP Content-Length头与实际文件数据所发送的字节数相匹配。或者您可以使用HTTP 1.1的分块传输编码,它不使用Content-Length头(因此您不需要提前知道文件大小)。POST(或HTTP)没有任何关于您在代码中如何发送字节的概念。因此,您需要做的就是循环读取文件数据,使用适当大小的内存缓冲区,在每次读取后通过套接字发送该缓冲区的内容,直到达到EOF。
例如(伪代码):
sckt = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
connect(sckt, "hostname", 80)
send(sckt, "POST /resource HTTP/1.0\r\n")
send(sckt, "Content-Type: application/octet-stream\r\n"); // or the actual file type
send(sckt, "Content-Length: " + string(the file size) + "\r\n")
send(sckt, "\r\n")
byte buffer[256] // use whatever buffer size is appropriate for your device
do
{
numread = read(file, buffer, sizeof(buffer));
if (numread <= 0) break;
send(sckt, buffer, numread);
}
while (true);
read HTTP response from sckt ...
或者:
sckt = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
connect(sckt, "hostname", 80)
send(sckt, "POST /resource HTTP/1.1\r\n")
send(sckt, "Content-Type: application/octet-stream\r\n"); // or the actual file type
send(sckt, "Transfer-Encoding: chunked\r\n")
send(sckt, "\r\n")
byte buffer[256] // use whatever buffer size is appropriate for your device
char hex[12]
do
{
numread = read(file, buffer, sizeof(buffer));
if (numread <= 0) break;
sprintf(hex, "%x", numread);
send(sckt, string(hex) + "\r\n")
send(sckt, buffer, numread)
send(sckt, "\r\n")
}
while (true);
send(sckt, "0\r\n");
send(sckt, "\r\n");
read HTTP response from sckt ...
即使是强大的桌面电脑也必须这样做,因为通常情况下无法一次性将整个文件放入内核缓冲区中,因此发送必须相应地循环进行。
嵌入式设备具有UDP和TCP套接字,但是要发送HTTP POST请求,例如,我需要创建一个包含HTTP头和数据的字符串。
您不需要在单个字符串中一次发送所有内容。您可以根据需要将其分成多个字符串/发送。 TCP是一种流传输协议,它不关心您执行了多少次发送,只要发送的字节按正确的顺序即可。您甚至可以每次发送一个字节(尽管效率不高,但它仍然能正常工作)。
由于设备没有HTTP协议或其他协议可用作API,所以不需要。由于HTTP建立在TCP之上,并且您可以访问TCP套接字API,因此可以手动实现HTTP。
HTTP已经完全可以胜任这项任务。
协议需要相对简单,不使用太多内存资源,如果您知道一个专门针对小型嵌入式设备设计的库,那就更好了。最好在接收服务器上实现协议,该服务器最好运行.Net。
HTTP非常适合这个任务。