使用winsock发送POST数据(并使用PHP服务器端脚本接收它们)
所以我想我应该玩一下 HTTP 并尝试将简单的纯文本(未编码)文本从我的程序发送到服务器。然而,有些事情不对劲,我也不知道是什么。
这是服务器端 PHP 脚本,我通过从 HTML 表单发送 POST 数据对其进行了测试,它运行得很好,所以我想服务器端没有任何问题。
<?php
$file = 'postData.txt';
$somecontent = $_POST['dat'];
$fp = fopen($file, 'w') or die('Could not open file!');
fwrite($fp, "$somecontent") or die('Could not write to file');
fclose($fp);
?>
这是程序(此代码包括一些未使用的部分,例如读取缓冲区中的文件内容等,那是因为我一直在玩它并且每 5 秒更改一次内容,不要介意):
#include <windows.h>
#include "WinSock2.h"
#include <stdio.h>
#include <stdint.h>
#include <iostream>
int main()
{
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
return 0;
SOCKET fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd < 0) throw;
SOCKADDR_IN service;
service.sin_family = AF_INET;
service.sin_port = htons(80);
LPHOSTENT host = gethostbyname("123.17.25.123");
if (!host) throw;
service.sin_addr = *((LPIN_ADDR)*host->h_addr_list);
if (connect(fd, (SOCKADDR *)&service, sizeof(service)) < 0) throw;
FILE *f = fopen("file.txt", "rb");
if (!f) throw;
uint32_t len = 0;
fseek(f, 0x00, SEEK_END);
len = ftell(f);
fseek(f, 0x00, SEEK_SET);
char header[1024];
char *buffer = new char[len];
fread(buffer, sizeof(char), len, f);
sprintf(header,
"POST /recv.php HTTP/1.1\r\n"
"Host: 123.17.25.123\r\n"
"User-Agent: Mozilla Firefox/4.0\r\n"
"Content-Length: %d\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Accept-Charset: utf-8\r\n\r\n",
len+4);
std::cout << header << std::endl;
send(fd, header, strlen(header), 0);
send(fd, "dat=", 4, 0);
send(fd, buffer, strlen(buffer), 0);
send(fd, "\r\n", 2, 0);
delete [] buffer;
fprintf(stderr, "Done\n");
closesocket(fd);
WSACleanup();
return 0;
}
那么,它有什么问题?有人知道吗? :P
edit1:我用wireshark监控流量并尝试运行该程序几次,但没有捕获任何数据包。奇怪的是,它甚至没有向任何地方发送任何东西。
edit2:感谢 TokenMacGuy 让它工作起来。上面的代码很蹩脚,但它会读取所有文件内容并将其作为 POST 数据发送到您的服务器,希望它对像我这样的菜鸟学习有用。再次感谢您!
So I thought I would play with HTTP a bit and try to send simple plain(not encoded) text from my program to a server. However, something is not right and I don't know what.
Here is the server side PHP script, I have tested it by sending POST data from HTML form and it worked just great, so I guess there isn't anything wrong on server side.
<?php
$file = 'postData.txt';
$somecontent = $_POST['dat'];
$fp = fopen($file, 'w') or die('Could not open file!');
fwrite($fp, "$somecontent") or die('Could not write to file');
fclose($fp);
?>
Here is the program(this code includes some unused parts like reading file content in buffer etc., that's cuz I am playing with it all the time and changing stuff every 5 seconds, don't mind it):
#include <windows.h>
#include "WinSock2.h"
#include <stdio.h>
#include <stdint.h>
#include <iostream>
int main()
{
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
return 0;
SOCKET fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (fd < 0) throw;
SOCKADDR_IN service;
service.sin_family = AF_INET;
service.sin_port = htons(80);
LPHOSTENT host = gethostbyname("123.17.25.123");
if (!host) throw;
service.sin_addr = *((LPIN_ADDR)*host->h_addr_list);
if (connect(fd, (SOCKADDR *)&service, sizeof(service)) < 0) throw;
FILE *f = fopen("file.txt", "rb");
if (!f) throw;
uint32_t len = 0;
fseek(f, 0x00, SEEK_END);
len = ftell(f);
fseek(f, 0x00, SEEK_SET);
char header[1024];
char *buffer = new char[len];
fread(buffer, sizeof(char), len, f);
sprintf(header,
"POST /recv.php HTTP/1.1\r\n"
"Host: 123.17.25.123\r\n"
"User-Agent: Mozilla Firefox/4.0\r\n"
"Content-Length: %d\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Accept-Charset: utf-8\r\n\r\n",
len+4);
std::cout << header << std::endl;
send(fd, header, strlen(header), 0);
send(fd, "dat=", 4, 0);
send(fd, buffer, strlen(buffer), 0);
send(fd, "\r\n", 2, 0);
delete [] buffer;
fprintf(stderr, "Done\n");
closesocket(fd);
WSACleanup();
return 0;
}
So, what's wrong with it? Does anyone have any idea? :P
edit1: I monitored the traffic with wireshark and tried to run the program few times, but no packets were captured. Strange, it does not even send anything anywhere.
edit2: Thanks to TokenMacGuy got it working. Code above is lame, but it will read all file content and send it as POST data to your server, hopefully it will be useful for noobs like me to learn. Thank you once again!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您没有收到数据,因为您实际上没有发送任何数据。尽管
buffer
出现在sprintf
中,但没有格式说明符来使用它(仅格式化长度)。尝试从 sprintf 调用中完全删除
buffer
,然后调用send
两次,一次用于标头(就像您已经做的那样),另一次用于发送实际数据。或者您可能不打算发送您读取的文件中的任何数据。您只想获取
dat=somedatar
。问题是您将内容类型指定为text/plain
,在这种情况下,服务器根本不会解释它。内容类型可能应该是application/x-www-form-urlencoded
。由于dat
参数是正文的一部分,因此content-length
标头必须包含它。如果内容长度与作为内容发送的实际字节数不匹配,符合要求的服务器将忽略整个请求(通常返回 400-499 范围的响应代码)。You aren't recieving the data because you aren't actually sending any data. Although
buffer
appears in thesprintf
, there's no format specifier to consume it (only the length is formatted).Try removing the
buffer
from the sprintf call altogether, and then callsend
twice, once for the headers (as you already do) and again to send the actual data.Or maybe you don't intend to send any data from the file you read. You just want to get that
dat=somedatar
. The problem is that you indicate the content-type astext/plain
, in which case the server won't interpret it at all. The content type should probably beapplication/x-www-form-urlencoded
. Since thedat
parameter is part of the body, thecontent-length
header must include it. If the content length doesn't match the actual number of bytes sent as content, conforming servers ignore the whole request (usually returning a 400-499 range response code).POST 应该在数据之前有两个换行符,而不是在数据之后。
POST should have two newlines before the data, not after it.