Introduction

Ever needed a quick way to get around to post text to a web server and get a response accordingly ? Look no further.  In this article i give the reader a class with 2 methods for testing the availability of the connection and for posting information. 

Background  

I used this code to post major text files, line by line, of summaries on PocketPC (Windows Mobile) to a statistical web site via an ASP file.    

Using the code 

While under Windows, you can send information on an open socket and read information  from the same spot.  This is nothing new, but using a socket to post to an internet server can be tricky, especially getting the 'post' syntax absolutly flauless.

As you can see on the header and body text below this paragraph,  there is a macro SEND_RQ just for passing clear text values, so not to get misslead by any strange char in C/C++ strings. 

#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;
    <span class="Apple-tab-span" style="white-space: pre; ">	</span>sockaddr_in			sin;
    <span class="Apple-tab-span" style="white-space: pre; ">	</span>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;
}
 

The testing method allows the class client to perceive its readness to post, that is evaluates the  presence of an connection - this may be important if working with windows mobile, because you may want the application to post only while docking (via usb or whatever) to a connected machine - therefore saving money on internet calls. 

If used on an already always connected  (tipically a PC) machine, you may only post with a specific  schedule, its up to you. 

Points of Interest  

I tried many syntaxes for the http post, and after carefull W3C reviewing i found that this is the one that works: 

	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");

Of course you will understand the variables better after adding the class to a client project and doing a debug session if you want, of course the names are fairly descriptive. 

After the POST is done the  ASP code is fairly simple, i mean you can just get the QueryString values and parse each variable that reaches the page, process it and return on the Response object an acknoledgement code return value. 

On the end of the method you can see a 'message' return pattern matching for codes. I used 'E01',etc to return coding information from the ASP  

History  

- C/C++ header and body 

推荐.NET配套的通用数据层ORM框架:CYQ.Data 通用数据层框架