【问题标题】:Send a struct using socket over http通过 http 使用套接字发送结构
【发布时间】:2015-10-26 03:40:23
【问题描述】:

我想使用 send() 和 recv() 通过 http 传输一个结构(有数据和 ID 等)。在 TCP 上,以下两行完美运行。

Client: send(sock, (char *)&StructToSend, sizeof(StructToSend), 0);
Server: recv(sock, (char *)&StructToRecv,  sizeof(StructToRecv),0); 

但是当通过 HTTP 时,StructToRecv 只得到两个字节的混乱代码,如下所示:ÈÈ

    ////Client code: send over http
    int length = 0;
    char header[4096];
    char tmp_name[80];
    memset(tmp_name, 0, sizeof(tmp_name));
    strcat_s(tmp_name, "tmp.txt");

    length  = (sizeof(SendStruct)+strlen(tmp_name)+ 287);

    sprintf_s(header, "POST /%s/index.html HTTP/1.1\r\n", sub_dir;
    sprintf_s(header, "%sHost: %s \r\n", header , szIP);
    sprintf_s(header, "%sUser-Agent: Mozilla/5.0 (Windows NT 6.1; rv:32.0) Gecko/20100101 Firefox/32.0\r\n", header);
    sprintf_s(header, "%sAccept: text/html;q=0.9,*/*;q=0.8\r\n", header);
    sprintf_s(header, "%sAccept-Language: en-US,en;q=0.5\r\n", header);
    sprintf_s(header, "%sAccept-Encoding: gzip, deflate\r\n", header);
    sprintf_s(header, "%sConnection: Keep-Alive\r\n", header);
    sprintf_s(header, "%sContent-Type: multipart/form-data; boundary=-----------------------------26774670897926\r\n", header);
    sprintf_s(header, "%sContent-Length: %d\r\n", header, length );
    sprintf_s(header, "%s\r\n", header);  //blank line
    sprintf_s(header, "%s-------------------------------26774670897926\r\n", header);
    sprintf_s(header, "%sContent-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n", header, tmp_name);
    sprintf_s(header, "%sContent-Type: text/plain\r\n", header);
    sprintf_s(header, "%s\r\n", header);  //blank line
    sprintf_s(header, "%s%s\r\n", header,  (char *)&StructToSend );
    sprintf_s(header, "%s-------------------------------26774670897926\r\n", header);
    sprintf_s(header, "%sContent-Disposition: form-data; name=\"submit\"\r\n", header);
    sprintf_s(header, "%s\r\n", header);
    sprintf_s(header, "%sSubmit\r\n\r\n", header);
    sprintf_s(header, "%s-------------------------------26774670897926--\r\n\r\n\0", header);      

    send(sock, header, sizeof(header), 0);


    ////Server code : recv over http 
    char http_data[4096] = { '\0' };
    ZeroMemory( http_data, sizeof( http_data));
    recv(sock,  http_data,  4096, 0);

【问题讨论】:

  • 您的一个sprintf_s() 调用缺少右括号;显示的代码无法编译。 sprintf_s() 的 C11 附件 K 定义是:int sprintf_s(char * restrict s, rsize_t n, const char * restrict format, ...); 尽管 Microsoft 可能不完全匹配(int sprintf_s(char *buffer, size_t sizeOfBuffer, const char *format [, argument] ... );,但您没有将大小作为第二个参数传递,这是一种可怕的作弊。您也无法可靠地传递目标字符串 (header) 作为要处理的参数之一 - 它会产生未定义的行为。重新思考!
  • 请注意,不建议以这种方式(通过 HTTP、TCP 或任何其他协议)发送结构体,因为不保证结构体的内存布局在两侧都相同网络连接,如果它不同,那么接收器将误解传入的数据。发送数据的正确方法是作为文本,或者通过 member-data-item 的 member-data-item,以便很好地定义在线数据格式。 (很多程序员选择使用序列化库来为他们处理这个任务)
  • @JeremyFriesner 我不应该使用第三个库。我该如何解决?
  • 数据序列化是它自己的话题,所以我无法在评论中提供足够的答案,但这里有一个链接可以帮助您入门:*.com/search?q=how+to+serialize+data+%5Bc%5D

标签: c sockets http


【解决方案1】:
sprintf_s(header, "%s%s\r\n", header,  (char *)&StructToSend );

您正在使用sprintf(...%s..)。这意味着您提供的数据将被视为以\0 结尾的字符字符串,即仅包含直到第一个\0 的数据。

【讨论】:

  • 我应该使用什么?请问有什么代码建议吗?
  • 我应该先将 StructToSend 转换为 char 字符串吗?
  • @MinKim:您不能将任何字符串函数(如 sprintf、strcpy、strlen 等)用于包含 \0 的二进制数据。字符串函数仅用于(非二进制)字符串,其他一切都使用 memcpy 和类似函数。
  • 您甚至不应该尝试通过网络发送二进制结构表示。灾难的秘诀。
  • 你能写代码吗?我的结构包含 int、DWORD 和数据(用于传输文件内容)
最近更新 更多