服务器代码
using namespace std;
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include<map>
#include <fstream>
#include<string>
#include <ctime>
#include<iostream>
using namespace std;
//最大传输大小
#define MAXSIZE 1024
#define SERVER_PORT 80
#define BACKLOG 10
//按行读取接收报文
string ReadLine(char recieve[], int &loc)
{
int next_char;
string data = "";
while (true)
{
next_char = recieve[loc++];
if (next_char == '\n')
{
break;
}
else if (next_char == '\r')
{
continue;
}
else if (next_char == '\0')
{
break;
}
data += next_char;
}
return data;
}
//处理HTTP请求类
class HttpRequestHandle {
public:
//初始化
HttpRequestHandle(unsigned char recieved[]) {
memcpy(recieve, recieved, MAXSIZE);
loc = 0;
Http_method = "";
Http_url = "";
}
//获得请求头
void GetHeadInfo() {
string line;
string head = ReadLine(recieve, loc);//请求行
//获得方法
int loc_head = 0;
while (head[loc_head] != ' ') {
Http_method += head[loc_head];
loc_head++;
}
loc_head++;
while (head[loc_head] != ' ') {
Http_url += head[loc_head];
loc_head++;
}
while ((line = ReadLine(recieve, loc)) != "") {
//分解报文头
int seq_index = line.find_first_of(":");
if (seq_index != -1) {
string type = line.substr(0,seq_index);
string value = line.substr(seq_index+1,line.size());
HttpHeaders.insert(make_pair(type,value));
}
cout << line << endl;
}
}
void GetHttpBody() {
while (recieve[loc] != '\0') {
body += recieve[loc];
loc++;
}
}
string GetMethod() {
return Http_method;
}
string GetURL() {
return Http_url;
}
string GetBody() {
return body;
}
private:
char recieve[MAXSIZE];//接收字符
string Http_method;//请求方式
string Http_url;//URL地址
string body;
map<string, string> HttpHeaders;
int loc;//读取位置
};
//处理方法类
class MyFunction {
public:
MyFunction(string Http_method, string Http_url, string body) {
this->body = body;
this->Http_method = Http_method;
this->Http_url = Http_url;
}
string Deal() {
string deal_str = "";
if (Http_method == "GET") {
int id = chooseGet();
switch (id) {
case 0:
deal_str = index("测试.html");
break;
case 1:
deal_str = index("hello.html");
break;
default:
break;
}
}
else if (Http_method == "POST") {
int id = choosePOST();
cout<<"POST Body-------->"<<body<<endl;
switch (id) {
case 0:
deal_str = index("测试.html");
break;
case 1:
deal_str = index("hello.html");
break;
default:
break;
}
}
return deal_str;
}
//根据GET的URL选择方法
int chooseGet() {
if (Http_url == "/") {
//如果为加载主页面
return 0;
}
else if(Http_url == "/hello"){
//测试URL
return 1;
}
else {
return -1;
}
}
//根据POST的URL和Body选择方法
int choosePOST() {
if (Http_url == "/") {
//如果为加载主页面
return 0;
}
else if(Http_url == "/hello"){
//测试URL
return 1;
}
else {
return -1;
}
}
//方法1:测试用
string test() {
return "hello";
}
//获得HTML页面
string index(string filename){
fstream fin;
fin.open(filename.c_str(), ios::in);
if(!fin){
cout<<"文件不存在"<<endl;
return "";
}
string v = "";
string tmp;
while (getline(fin, tmp)) {
v += tmp;
}
fin.close();
return v;
}
private:
string Http_method;//请求方式
string Http_url;//URL地址
string body;
};
class HttpResponseHandle {
public:
HttpResponseHandle(string send) {
this->send = send;
Http_State = "200";//成功状态
Http_phrase = "OK";
Http_protocol_versionstring = "HTTP/1.1";
HttpHeaders.insert(make_pair("Connection","keep-alive" ));
HttpHeaders.insert(make_pair("Server","C++" ));
HttpHeaders.insert(make_pair("Content-Type","text/html;charset=UTF-8"));
}
void SetSend() {
string headerstr = "";
headerstr = Http_protocol_versionstring + " " + Http_State + " " + Http_phrase + "\r\n";
string Header_line = "";
map<string, string>::reverse_iterator iter;
//HttpHeaders["Content-Length"] = ""+send.size();
for (iter = HttpHeaders.rbegin(); iter != HttpHeaders.rend(); iter++) {
Header_line += iter->first + ":" + iter->second + "\r\n";
}
headerstr += Header_line ;
send = headerstr + "\r\n" + send+'\0';
cout<<"send----->"<<send<<endl;
}
string GetSend() {
return send;
}
private:
string Http_State;
string Http_phrase;
string Http_protocol_versionstring;
string Content_Type;
map<string, string> HttpHeaders;
string send;
};
struct s_info { //定义一个结构体, 将地址结构跟cfd捆绑
struct sockaddr_in cliaddr;
int connfd;
};
void *do_work(void *arg){
struct s_info *ts = (struct s_info*)arg;
unsigned char ucRecvBuf[MAXSIZE];
int iRecvLen = 0;
while(1){
iRecvLen = read(ts->connfd, ucRecvBuf, MAXSIZE);
if(iRecvLen==0){
printf("the client %d closed...\n", ts->connfd);
break;
}
cout<<"Request:"<<ucRecvBuf<<endl;
HttpRequestHandle httpreq(ucRecvBuf);
httpreq.GetHeadInfo();
httpreq.GetHttpBody();
MyFunction function(httpreq.GetMethod(), httpreq.GetURL(), httpreq.GetBody());
string response_str = function.Deal();
HttpResponseHandle response(response_str);
response.SetSend();
string send_str = response.GetSend();
cout<<"Response:"<<send_str<<endl;
write(ts->connfd, send_str.c_str(), strlen(send_str.c_str()));
}
close(ts->connfd);
printf("close socket\n");
close(ts->connfd);
return (void *)0;
}
int main()
{
struct sockaddr_in servaddr, cliaddr;
socklen_t cliaddr_len;
int listenfd, connfd;
pthread_t tid;
struct s_info ts[256]; //根据最大线程数创建结构体数组.
int i = 0;
listenfd = socket(AF_INET, SOCK_STREAM, 0); //创建一个socket, 得到lfd
int option = 1;
setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&option,sizeof(option));
bzero(&servaddr, sizeof(servaddr)); //地址结构清零
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); //指定本地任意IP
servaddr.sin_port = htons(SERVER_PORT); //指定端口号 8000
if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr))==-1) //绑定
{
printf("端口被占用\n");
}
listen(listenfd, 128); //设置同一时刻链接服务器上限数
printf("Accepting client connect ...\n");
while (1) {
cliaddr_len = sizeof(cliaddr);
connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); //阻塞监听客户端链接请求
ts[i].cliaddr = cliaddr;
ts[i].connfd = connfd;
/* 达到线程最大数时,pthread_create出错处理, 增加服务器稳定性 */
pthread_create(&tid, NULL, do_work, (void*)&ts[i]);
pthread_detach(tid); //子线程分离,防止僵线程产生.
i++;
}
return 0;
}
模拟请求
测试.html
<!DOCTYPE html>
<html>
<head>
<title>测试HTTP请求</title>
</head>
<body>
<p style="font-family:arial;font-size:30px;text-align:center">模拟HTTP请求</p><hr>
<p style="font-family:arial;font-size:25px;text-align:center">
URL:<input type="text" name="port" id="url"><hr>
</p>
<p style="font-family:arial;font-size:25px;text-align:center">
Method:
<input type="radio" name="method" value="GET" checked>GET
<input type="radio" name="method" value="POST" >POST
<hr>
</p>
</p>
<p style="font-family:arial;font-size:25px;text-align:center">
BODY:<br>
<textarea rows="10" cols="30" id="body">
json报文
</textarea>
</p>
<hr>
<p style="font-family:arial;font-size:25px;text-align:center">
<input type="submit" value="提交" onclick="SendRequest()">
<input type="submit" value="清除">
</p>
<script>
function SendRequest() {
var URL = document.getElementById("url").value ;
var choose = document.getElementsByName("method");
var Method = "";
if(choose[0].checked){
Method = "GET";
}
else if(choose[1].checked){
Method = "POST";
}
else{
alert("请选择请求方式");
return;
}
var Body = document.getElementById("body").value;
if(Method=="GET"){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("body").value = xhttp.responseText;
}
else{
document.getElementById("body").value = xhttp.responseText;
}
};
xhttp.open("GET", URL);
xhttp.send();
}
else if(Method == "POST"){
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("body").value = xhttp.responseText;
}
else{
document.getElementById("body").value = xhttp.responseText;
}
};
xhttp.open("POST", URL);
xhttp.send("SDASDASDDDDDDDDDDDDDDFJDHJD");
}
else{
}
}
</script>
</body>
</html>
测试网页
hello.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>
你好
</h1>
</body>
</html>