1 wsclientpp
wsclientpp是在前面几天写的一个websocket的客户端,缺少纯http协议的客户端,为此而写。
git地址:地址
2 httpcliennt
只实现get协议和post协议,一发一收,还不完善,先写get协议,比较简单,凑字符串参数为host,port, path,和get_content, path为主要路由,get_content 为路径
2.1 get
int getData(const char* host, unsigned short port, const char* path, const char* get_content)
{
//GET请求方式
std::stringstream stream;
if(get_content!=NULL && strlen(get_content) > 0)
//if (strlen(get_content) > 0)
stream << "GET " << path << "?" << get_content;
else
stream << "GET " << path;
stream << " HTTP/1.0\r\n";
stream << "Host: " << host << "\r\n";
stream << "User-Agent: cool duck /1.1.1\r\n";
stream << "Connection:close\r\n\r\n";
//string temp = stream.str();
//cout << "len is " << temp.size() << endl;
return Http(host, port, stream.str().c_str());
}
2.2 post
依然是post
int postData(const char* host, unsigned short port, const char* path, const char* post_content)
{
//POST请求方式
std::stringstream stream;
stream << "POST " << path;
stream << " HTTP/1.0\r\n";
stream << "Host: " << host << "\r\n";
stream << "User-Agent: cool duck/1.1.1\r\n";
stream << "Content-Type:application/json\r\n";
//stream << "Content-Type:application/x-www-form-urlencoded\r\n";
stream << "Content-Length:" << strlen(post_content) << "\r\n";
stream << "Connection:close\r\n\r\n";
stream << post_content ;
//string temp = stream.str();
//cout << "temp is :" << temp << endl;
return Http(host, port, stream.str().c_str());
}
2.3 http 函数
int Http(const char* host, unsigned short port, const char *request)
{
SOCKET sockfd;
struct sockaddr_in address;
struct hostent *server;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_port = htons(port);
//getaddrinfo()
server = gethostbyname(host);
memcpy((char *)&address.sin_addr.s_addr, (char*)server->h_addr, server->h_length);
#ifdef _WIN32
int ret = 0;
//int timeout = 2000; //2s
//这样做在Linux环境下是不会产生效果的,须如下定义:
struct timeval timeout = {
2,0 };
//设置发送超时
setsockopt(sockfd,SOL_SOCKET,SO_SNDTIMEO,(char *)&timeout, sizeof(struct timeval));
//设置接收超时
setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,(char *)&timeout, sizeof(struct timeval));
// ret = setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout));
// ret = setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
#endif
if (-1 == connect(sockfd, (struct sockaddr *)&address, sizeof(address))) {
#ifdef _WIN32
closesocket(sockfd);
#endif
cout << "connection error!" << std::endl;
return -1;
}
#ifdef WIN32
int iRes = send(sockfd, request, (int)strlen(request), 0);
if (iRes == SOCKET_ERROR) {
printf("send failed: %d\n", WSAGetLastError());
closesocket(sockfd);
return -1;
}
#else
struct timeval timeout = {
2,0 };//2s
int ret = setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(timeout));
int ret = setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(timeout));
write(sockfd, request, strlen(request));
#endif
_data.clear();
#define BUF_SIZE 128
char buf[128+1];
//char * buf = new char[64];
int offset = 0;
int rc;
do {
int buflen = BUF_SIZE - offset;
if (buflen == 0)
{
printf("not enough mem,so continue\n");
offset = 0;
buflen = BUF_SIZE;
//break;
}
#ifdef WIN32
rc = recv(sockfd, buf + offset, buflen, 0);
//rc = recv(sockfd, buf + offset, buflen, MSG_WAITALL);
#else
rc = read(sockfd, buf + offset, 1024);
#endif
if (rc > 0) {
offset += rc;
buf[rc] = '\0';
_data += buf;
printf("Bytes received: %d\n", rc);
}
else if (rc == 0)
{
printf("Connection closed\n");
}
else
printf("recv failed: %d\n",rc);
} while (rc > 0);
#ifdef WIN32
closesocket(sockfd);
#else
close(sockfd);
#endif
cout << _data << endl;
//buf[offset] = 0;
//printf("%s\n", buf);
//_data = buf;
//delete[]buf;
#if 0
size_t r = _data.rfind("\r\n\r\n");
cout << "r is " << r << endl;
//cout << _data << std::endl;
string re = _data.substr(409 + 4);
cout << "the re is " << re << endl;
#endif
}
2.4 增加回调函数
定义回调
typedef void(*callback_http_recv)(void* pUser,const char* message, int len);
类中增加设置函数
void setcallback(callback_http_recv recv,void* puser)
{
v_recv = recv;
v_puser = puser;
}
在httpclient 中close之前调用回调
cout << _data << endl;
if (v_recv != NULL)
v_recv(v_puser, _data.c_str, (int)_data.size());
也就是说,我们接收的是纯返回的http内容,还没有解析,下一步要加上解析,所以还不完善,主要需要和wsclientpp 一样,修改成select方式,现在还是阻塞模式,测试程序也没有封装多,也没有放入回调函数,先加入wsclientpp库中,依然是一个头文件,以下是测试程序
#include <iostream>
#include "../CorePhone/httpclient.h"
#ifdef _WIN32
#pragma comment(lib,"ws2_32")
#endif
int main()
{
http_connect conn;
conn.getData("127.0.0.1", 8000, "/", NULL);
conn.getData("127.0.0.1", 8000, "/test", NULL);
getchar();
//std::cout << "Hello World!\n";
}
写一个nodejs的http server 测试,以后还是用python写,这次还是用node
var express = require('express');
var app = express();
var http = require('http').Server(app);
var httpget = require('http');
//var bodyParser = require('body-parser');
var session = require('express-session');
//var rw = require('./config.js');
//在线
//app.use(bodyParser.urlencoded({ extended: false }))
//app.use(bodyParser.json());
app.use(session({
secret: 'secret',
resave: true,// don't save session if unmodified
saveUninitialized: false,// don't create session until something stored
cookie: {
maxAge: 1000 * 60 * 10 //过期时间设置(单位毫秒)
}
}));
app.use(express.static(__dirname));
app.get("/",function(req,res){
res.send("{ret:ok}");
});
http.listen(8000, function () {
console.log('listening on *:8000');
});
读者自行修改,进行测试,现在吗,http和websocket client都有了。
git地址:地址