65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (8投票s)

2011 年 2 月 13 日

CPOL

2分钟阅读

viewsIcon

19598

使用简洁的 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.
© . All rights reserved.