【转】socket提交http表单 [C++]
【http报文格式】:
【用牡丹园BBS做测试】:
首先查看BBS源代码:(右键分别在BBS不同的两个区域点击并查看源代码,得到如下结果)
【找到HTML源码中相应的变量和表格提交的地址并用程序实现】:
【成功的运行】:(当然经过了N次测试,同时还感谢Inkoo的大力支持)
【程序源代码】:
/***************code.h********************/
#ifndef _CODE_H_
#define _CODE_H_
#include <string>
using namespace std;
class CCode
{
public:
string Encode(const string & str);
string Decode(const string & str);
};
#endif
/*****************code.cpp*************************/
#include "code.h"
string CCode::Encode(const string & str)
{
string ret="";
char buf[20];
int i=0;
while(i<str.length())
{
if(str[i] & 0x80)
{
sprintf(buf,"%%%1X%1X",(unsigned char)str[i],(unsigned char)str[i+1]);
++i;
ret+=buf;
}
else
ret+=str[i];
++i;
}
return ret;
}
string CCode::Decode(const string & str)
{
string ret="";
string cur,all=str;
while(all.length()>0)
{
int pos=all.find("%");
if(pos!=0)
ret+=all.substr(0,pos);
cur=all.substr(pos+1,2);
all=all.substr(pos+3);
char ch;
sscanf(cur.c_str(),"%x",&ch);
ret+=(char)ch;
}
return ret;
}
/*************************http.h***************************/
#ifndef _HTTP_H_
#define _HTTP_H_
#include <winsock2.h>
#include <iostream>
#include <string>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
#define BUFFER_SIZE 11400
class CHttp
{
public:
CHttp();
virtual ~CHttp();
private:
SOCKET m_SOCKET;
WSADATA m_WSADATA;
HOSTENT * m_HOSTENT;
SOCKADDR_IN m_SOCKADDR_IN;
char buf[BUFFER_SIZE];
int len;
private:
bool CreateSocket();
void ReleaseSocket();
public:
bool Connect(const string & httpAddr,const int port=80);
int SendData(const char * str);
string RecvData();
};
#endif
/************************http.cpp******************************/
#include "http.h"
void msg(char * str)
{
#ifdef _DEBUG
cout<<str<<endl;
#endif
}
CHttp::CHttp()
{
}
CHttp::~CHttp()
{
}
bool CHttp::CreateSocket()
{
if(WSAStartup(MAKEWORD(2,2),&m_WSADATA)==SOCKET_ERROR)
{
msg("wsastartup");
ReleaseSocket();
return false;
}
if((m_SOCKET=socket(AF_INET,SOCK_STREAM,0))==SOCKET_ERROR)
{
msg("socket");
ReleaseSocket();
return false;
}
return true;
}
void CHttp::ReleaseSocket()
{
shutdown(m_SOCKET,SD_BOTH);
closesocket(m_SOCKET);
WSACleanup();
}
bool CHttp::Connect(const string & httpAddr,const int port)
{
if(! CreateSocket())
return false;
if((m_HOSTENT=gethostbyname(httpAddr.c_str()))==NULL)
{
msg("gethostbyname");
ReleaseSocket();
return false;
}
if(m_HOSTENT->h_addr_list[0]==NULL)
{
msg("h_addr_list");
ReleaseSocket();
return false;
}
memset(&m_SOCKADDR_IN,0,sizeof(m_SOCKADDR_IN));
m_SOCKADDR_IN.sin_family=AF_INET;
m_SOCKADDR_IN.sin_port=htons(port);
m_SOCKADDR_IN.sin_addr.S_un.S_addr=*(ULONG *)m_HOSTENT->h_addr_list[0];
int timeOut=5000;
if(::setsockopt(m_SOCKET,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeOut,sizeof(timeOut))==SOCKET_ERROR)
return false;
if(connect(m_SOCKET,(sockaddr *)&m_SOCKADDR_IN,sizeof(m_SOCKADDR_IN))==SOCKET_ERROR)
{
msg("connect");
ReleaseSocket();
return false;
}
return true;
}
string CHttp::RecvData()
{
try
{
len=recv(m_SOCKET,buf,sizeof(buf),0);
if(len==SOCKET_ERROR)
return "";
buf[len]=0;
return string(buf);
}
catch(...)
{
return "";
}
}
int CHttp::SendData(const char * str)
{
return send(m_SOCKET,str,strlen(str),0);
}
/**************************main.cpp**************************/
#pragma warning (disable:4786)
#include <iostream>
#include <sstream>
#include <iterator>
#include <vector>
#include "http.h"
#include "code.h"
using namespace std;
string StoreCookies(const string & strRecv) //从登陆接收的数据中分离出Cookie信息合并成发送的格式
{
string sCookies;
istringstream ssin(strRecv);
string line;
while(! getline(ssin,line).eof())
{
if(line.find("cookie")!=string::npos)
{
int pos[2];
if((pos[0]=line.find("\'",0))!=string::npos && (pos[1]=line.find("\'",pos[0]+1))!=string::npos)
{
if(sCookies.length()>0)
sCookies+=";";
sCookies+=line.substr(pos[0]+1,pos[1]-pos[0]-1);
}
}
}
return sCookies;
}
int main()
{
CHttp http;
http.Connect("bbs.jlu.edu.cn");
/******************登陆BBS并提取Cookie*********************/
string login="POST /cgi-bin/bbslogin HTTP/1.1\r\n";
login+="Content-Type: application/x-www-form-urlencoded\r\n";
login+="Host: bbs.jlu.edu.cn\r\n";
login+="Content-Length: 27\r\n\r\n"; //HTTP头结束,两个"\r\n"
login+="id=luosiyong&pw='yourpwd'\r\n\r\n"; //提交表单内容 这里pw经过了处理
http.SendData(login.c_str());
string sRecv=http.RecvData();
cout<<"login response >>>>>>\n"<<sRecv<<endl;
string sCookie=StoreCookies(sRecv); //从登陆的信息提取cookie用于后面验证
/*******************发帖*************************************/
string post="POST /cgi-bin/bbssnd?board=Arctic&u=0&r=0 HTTP/1.1\r\n";
post+="Content-Type: application/x-www-form-urlencoded\r\n";
post+="Host: bbs.jlu.edu.cn\r\n";
post+="Content-Length: 50\r\n";
post+="Cookie: \r\n\r\n";
post+="title=测试&signature=1&text=文本!@#$^*()_+|[]'内容\r\n"; //注意不能包含%和&符号,它们在HTTP中用于转义和变量连接
post.insert(post.find("Cookie: ")+strlen("Cookie: "),sCookie); //在http头中加入Cookie信息
http.SendData(post.c_str());
cout<<http.RecvData()<<endl;
/*******************注销登陆**********************************/
string logout="GET /cgi-bin/bbslogout HTTP/1.1\r\n";
logout+="Host: bbs.jlu.edu.cn\r\n";
logout+="Cookie: \r\n\r\n";
logout.insert(logout.find("Cookie: ")+strlen("Cookie: "),sCookie);
http.SendData(logout.c_str());
cout<<http.RecvData()<<endl;
return 0;
}
本文使用Blog_Backup未注册版本导出,请到soft.pt42.com注册。