使用 Windows 套接字(C 语言)发布到 ASP 网站






4.92/5 (8投票s)
使用简洁的 C/C++ 类,通过 Windows 套接字轻松向互联网服务器发布数据。
引言
是否曾经需要一种快速的方法来向 Web 服务器发布文本并相应地获取响应? 不再需要寻找。 在本文中,我向读者提供了一个类,其中包含两种方法,用于测试连接的可用性和发布信息。
背景
我使用这段代码逐行发布大型文本文件(摘要)到 PocketPC(Windows Mobile)上的统计网站,通过 ASP 文件实现。
Using the Code
在 Windows 下,您可以从同一个位置发送信息到打开的套接字并读取信息。 这没什么新鲜的,但是使用套接字向互联网服务器发布可能很棘手,尤其是确保“post”语法绝对无误。
如您在以下段落的标题和正文文本中看到的,有一个宏 SEND_RQ
专门用于传递纯文本值,因此不要被 C/C++ 字符串中的任何奇怪字符所误导。
#define _DEBUG_PRINT(X) /* X */
#include <iostream>
#include <string>
#include <stdlib.h>
#include <assert.h>
#include <Winsock2.h>
#define VERSION_MAJOR 1;
#define VERSION_MINOR 1;
#define CRLF "\r\n" // carriage-return/line feed pair
#define SEND_RQ(MSG) send(sock,MSG, (int) strlen(MSG),0);
using namespace std;
class CHttp
{
public:
WSADATA WsaData;
sockaddr_in sin;
size_t sock ;
CHttp(void);
~CHttp(void);
int TestConnectionToHostName (char* hostname);
int Post (char* hostname, char* api, char* parameters, string& message);
};
#include "StdAfx.h"
#include "CHttp.h"
CHttp::CHttp(void)
{
}
CHttp::~CHttp(void)
{
}
int CHttp::TestConnectionToHostName (char* hostname)
{
WSAStartup (0x0101, &WsaData);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
return -100;
}
sin.sin_family = AF_INET;
sin.sin_port = htons( (unsigned short)80);
struct hostent * host_addr = gethostbyname(hostname);
if(host_addr==NULL)
{
return -101;
}
sin.sin_addr.s_addr = *((int*)*host_addr->h_addr_list) ;
if( connect (sock,(const struct sockaddr *)&sin, sizeof(sockaddr_in) ) == -1 )
{
return -102;
}
WSACleanup( );
return 0;
}
int CHttp::Post (char* hostname, char* api, char* parameters, string& message)
{
WSAStartup (0x0101, &WsaData);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == -1)
{
return -100;
}
sin.sin_family = AF_INET;
sin.sin_port = htons( (unsigned short)80);
struct hostent * host_addr = gethostbyname(hostname);
if(host_addr==NULL)
{
return -101;
}
sin.sin_addr.s_addr = *((int*)*host_addr->h_addr_list) ;
if( connect (sock,(const struct sockaddr *)&sin, sizeof(sockaddr_in) ) == -1 )
{
return -102;
}
string send_str;
char content_len[STRING_SIZE_256];
sprintf(content_len,"Content-Length: %d\r\n",strlen(parameters));
char host_api[STRING_SIZE_256];
strcpy(host_api, "http://");
strcat(host_api, hostname);
strcat(host_api, api);
SEND_RQ("POST "); SEND_RQ(host_api); SEND_RQ(" HTTP/1.0\r\n");
SEND_RQ("From: any@sidegence.com\r\n");
SEND_RQ("User-Agent: Mozilla/4.0\r\n");
SEND_RQ("Content-Type: application/x-www-form-urlencoded\r\n");
SEND_RQ(content_len);
SEND_RQ("\r\n");
SEND_RQ(parameters);
SEND_RQ("\r\n");
char c1[1];
int l,line_length;
bool loop = true;
bool bHeader = false;
while(loop)
{
l = recv(sock, c1, 1, 0);
if(l<0)
loop = false;
if(c1[0]=='\n')
{
if(line_length == 0)
loop = false;
line_length = 0;
if(message.find("200") != string::npos)
bHeader = true;
}
else
if(c1[0]!='\r')
line_length++;
message += c1[0];
}
message="";
if(bHeader)
{
char p[1024];
while((l = recv(sock,p,1023,0)) > 0)
{
p[l] = '\0';
message += p;
}
}
else
{
return -103;
}
int index = (int) message.find("E01");
if (index>=0) return -104;
WSACleanup( );
return 0;
}
测试方法允许类 Client
感知其发布准备情况,即评估连接的存在性 - 这在使用 Windows Mobile 时可能很重要,因为您可能希望应用程序仅在连接到已连接机器时(通过 USB 或其他方式)发布 - 从而节省互联网通话费用。
如果在一台始终连接的机器(通常是 PC)上使用,您可能只想按照特定计划发布,这取决于您。
关注点
我尝试了许多 HTTP POST 语法,并在仔细审查 W3C 之后,我发现这是可行的语法。
SEND_RQ("POST "); SEND_RQ(host_api); SEND_RQ(" HTTP/1.0\r\n");
SEND_RQ("From: any@sidegence.com\r\n");
SEND_RQ("User-Agent: Mozilla/4.0\r\n");
SEND_RQ("Content-Type: application/x-www-form-urlencoded\r\n");
SEND_RQ(content_len);
SEND_RQ("\r\n");
SEND_RQ(parameters);
SEND_RQ("\r\n");
当然,如果您想将类添加到客户端项目并进行调试会话,您会更好地理解这些变量; 变量名称相当具有描述性。
POST 完成后,ASP 代码非常简单; 我的意思是,您可以获取 QueryString 值并解析到达该页面的每个变量,对其进行处理,并在 Response
对象上返回一个确认代码返回值。
在方法结束时,您可以看到用于代码匹配的“message”返回模式。 我使用“E01”等来从 ASP 端返回编码信息。
历史
- First version.