nginx + php + Ajax 学习
First step nginx和php的配置和启动
1.下载 nginx 和 php
2.nginx 配置与启动
打开nginx.conf文件
server {
listen 2333;//可以调整接口为2333(要确保未被占用)
server_name localhost;
location / {
root C:\Users\zhongzero\Desktop\interaction;//可以修改自己网站根目录的绝对路径
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
location ~ \.php$ {
root C:\Users\zhongzero\Desktop\interaction;
fastcgi_pass 127.0.0.1:9020;//php端口(要确保未被占用)
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
注:
netstat -aon|findstr "80"
查看:80接口是否被占用(因为nginx默认要占据:80接口)
(-a = -all)(-o 显示拥有的与每个连接关联的进程 ID)(-n以数字形式显示地址和端口号)(findstr "80"表示所有包含80这个字符串的信息)
若是发现被占用,通过上述命令可知占用:80接口的进程ID
tasklist|findstr "xxx” 查看该ID是哪个进程
启动nginx
./nginx.exe
nginx可在后端运行(即可以直接关闭运行它的命令行)
如要关闭nginx,找到相应进程kill(任务管理器/命令行 taskkill /pid xxxx -f) or 输入命令 .\nginx.exe -s quit
3.php配置与启动
把php.ini-development文件复制到php.ini
搜索 extension_dir,修改:
On Windows
extension_dir="./ext" (记得把左边的注释符号';'删除)
搜索cgi.fix_pathinfo 修改:
cgi.fix_pathinfo=1
搜索extension=sockets 修改:
extension=sockets (把左边的注释符号';'删除)
启动php
./php-cgi.exe -b 127.0.0.1:9020 -c php.ini (端口要和nginx中写的对上)
(不能把运行它的命令行关掉)
- 测试是否成功
在网页根目录下添加 phpinfo.php
<?php
phpinfo();
?>
在浏览器中打开localhost:2333/phpinfo.php,查看是否能成功访问
Step2 php语法学习 + Get/Post使用
1.php基础语法
<!-- PHP文件 包含 HTML标签 和 PHP脚本代码 -->
<html>
<body>
<h1>My first PHP page</h1>
<?php
$x=5;//$表示为变量
$y=6;
$z=$x+$y;
echo $z,"</br>";//echo输出,输出多个用","间隔,双引号表示直接输出字符串(相当于输出成一个html文件,最后由浏览器解析)
$Array=array("apple","banana","orange");//数组定义
foreach($Array as $x){//遍历数组
echo "Key=",$x,"</br>";//echo输出
}
?>
</body>
2.Get/Post在前后端(html,php)的使用
前端(test.html,用表单传递)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HTML form表单演示</title>
</head>
<body>
<form action="./userinfo.php" method="post">//用get则改成get(不区分大小写);传递数据给网站根目录下的useinfo.php,提交表单后会自动跳转到userinfo.php
<!-- 文本输入框控件 -->
<label>用户名: </label><input name="username" type="text"><br>
<!-- 密码框控件 -->
<label>密 码: </label><input name="password" type="password"><br>
<!-- 下拉菜单控件 -->
<label>性 别:</label>
<select name="sex">
<option value="1">男</option>
<option value="2">女</option>
<option value="3">未知</option>
</select>
<br>
<!-- 复选框控件 -->
<label>爱 好:</label>
<input type="checkbox" name="hobby" value="1">听音乐
<input type="checkbox" name="hobby" value="2">看电影
<input type="checkbox" name="hobby" value="3">打游戏
<br>
<!-- 单选按钮控件 -->
<label>学 历:</label>
<input type="radio" name="education" value="1">小学
<input type="radio" name="education" value="2">中学
<input type="radio" name="education" value="3">本科
<input type="radio" name="education" value="4">硕士
<input type="radio" name="education" value="5">博士
<br>
<!-- 按钮 -->
<input type="submit" value="提 交">  
<input type="reset" value="重 置">
</form>
</body>
</html>
后端(userinfo.php)
欢迎<?php echo $_POST["username"]; ?>!<br> <!-- 用get则改成get(区分大小写) -->
<!-- 下拉菜单、复选框、单选按钮等表单数据在后端读取的方法详见https://m.runoob.com/php/php-forms.html -->
打开 http://localhost:2333/d.html
在test.html中的表单提交后,会自动跳转到 http://localhost:2333/userinfo.php
3.Get/Post的区别
1.post发送的数据对任何人都是不可见的,get是可见的
以上为例
若用post提交,会跳转到 http://localhost:2333/userinfo.php
若用get提交,会跳转形如 http://localhost:2333/userinfo.php?username=zhongzero&password=123456&sex=1&hobby=1&hobby=3&education=1
post的好处在于安全,但get更快一些,而且由于get可见的特性,get提交后跳转的网址可以被保存在收藏夹中
2.get提交的数据大小受限
post不受限(虽然默认为8MB,不过可以随便调)
Step3 Ajax
Ajax 全称 Asynchronous(异步) JavaScript and XML
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。
传统的网页(不使用 AJAX)如果需要更新内容,必须重载整个页面。(如上的基于表单的测试)
更多可参考:https://www.runoob.com/ajax/ajax-tutorial.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script>
function loadXMLDoc()
{
var xmlhttp;//定义变量
if (window.XMLHttpRequest)
{
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp=new XMLHttpRequest();//创建一个XMLHttpRequest对象
}
else
{
// IE6, IE5 浏览器执行代码
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");//IE5,IE6不支持XMLHttpRequest,得使用这种方法
}
xmlhttp.onreadystatechange=function()//每当 readyState 属性改变时,就会调用该函数
{
if (xmlhttp.readyState==4 && xmlhttp.status==200){//表示已成功获取到数据
//readyState表示请求状态(0:未初始化,1:服务器连接已建立,2:请求已接收,3:请求处理中,4:请求已完成,且响应已就绪)
//status (200:OK,404:未找到页面)
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
//document.getElementById("myDiv")表示找到第一个id为myDiv的标签的引用
//这里做到了把找到的标签的内部html代码改成xmlhttp中获得到的
//xmlhttp.responseText返回的是string类型
//xmlhttp.responseXML返回的是xml类型,此时还需要对获取的文件进行进一步解析
}
}
//以下为POST请求方式
xmlhttp.open("POST","./userinfo.php",true);
//请求方式,请求地址,是否开启异步
//默认请开启异步
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
//设置html header
//html header一般作用是 告诉电脑应该用什么语言、什么规范之类的
//这里的参数表示的是允许传递变量中蕴含的内容(大概)
//更多header信息详见 https://kb.cnblogs.com/page/92320/
// xmlhttp.send("username=zhongzero&password=123456");
var username=document.getElementById("username").value;
var password=document.getElementById("password").value;
xmlhttp.send("username="+username+"&password="+password);
//Post在此传递参数
/*
//以下为Get请求方式
// xmlhttp.open("GET","./userinfo.php?username=zhongzero&password=123456",true);
var username=document.getElementById("username").value;
var password=document.getElementById("password").value;
xmlhttp.open("GET","./userinfo.php?username="+username+"&password="+password,true);
xmlhttp.send();
*/
}
</script>
</head>
<body>
<h2>AJAX</h2>
<div>
username
<input type="text" id="username">
</div>
<div>
password
<input type="password" id="password">
</div>
<button type="button" onclick="loadXMLDoc()">请求数据</button> <!-- 每次onclick时执行loadXMLDoc() js函数 -->
<div id="myDiv"></div> <!-- 一开始其中内容为空,点击上述按钮后,通过id索引找到此处位置,可将其中代码进行修改 -->
</body>
</html>
Step4 socket
通过socket使不同进程(php和C++)之间交互数据
php文件
<!-- 注意要改php.ini 中的extension socket -->
<?php
$sss=$_POST["username"];
$socket=socket_create(AF_INET, SOCK_STREAM, SOL_TCP);//创建一个socket
socket_connect($socket,'127.0.0.1',9030);//开始一个socket连接
socket_write($socket,$sss);//写数据到socket缓存
$res=socket_read($socket,300000);//300000为读取数据字节上界
echo $res;
// if($res=="-1")echo $res;
// else {
// }
?>
C++文件(Linux系统下)
#include<iostream>
#include<cstring>
#include <netinet/in.h>
#include <sys/socket.h>
string Solve(string order){
}
int main() {
// 创建套接字
int slisten = socket(AF_INET, SOCK_STREAM, 0);
//用来指定套接字使用的地址格式,通常使用AF_INET
//指定套接字的类型,此处用的是SOCK_DGRAM,表示为udp不可靠传输
//配合type参数使用,指定使用的协议类型(当指定套接字类型后,可以设置为0,因为默认为UDP或TCP)
// 填充sockaddr_in结构 ,是个结构体
/* struct sockaddr_in {
short sin_family; //地址族(指定地址格式) ,设为AF_INET
u_short sin_port; //端口号
struct in_addr sin_addr; //IP地址
char sin_zero[8]; //空子节,设为空
} */
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(9030);//端口号(1024 ~ 49151)
sin.sin_addr.s_addr = htonl(INADDR_ANY);
// 绑定这个套节字到一个本地地址
if (bind(slisten, (struct sockaddr *)&sin, sizeof(sin)) == -1){
printf("Failed bind()\n");
return 0;
}
// 进入监听模式
//5指的是,监听队列中允许保持的尚未处理的最大连接数
if (listen(slisten, 5) == -1) {
printf("Failed listen()\n");
return 0;
}
int sclient;
sockaddr_in client_add;
socklen_t naddrlen = sizeof(client_add);
char data[100000];
while (1) {
memset(data, 0, sizeof(data));
// 接受一个新连接
//(struct sockaddr *)&client_add 一个指向sockaddr_in结构的指针,用于获取对方地址
sclient = accept(slisten, (struct sockaddr *)&client_add, &naddrlen);
if (sclient == -1) {printf("Failed accept()");continue;}
//从客户端接收数据
recv(sclient, data, 100000, 0);
std::cout << "接受到一个连接:"<<data<<endl;
//处理数据
std::string result = Solve(data);
// 向客户端发送数据
send(sclient, result.c_str(), result.length(), 0);
}
return 0;
}
C++文件(Windows系统下)
#include <stdio.h>
#include <iostream>
#include <winsock2.h>
#include <stdlib.h>
#include <conio.h>
#include <stdio.h>
using namespace std;
class CInitSock{
public:
CInitSock(BYTE minorVer=2, BYTE majorVer=2){
// 初始化WS2_32.dll
WSADATA wsaData;
WORD sockVersion=MAKEWORD(minorVer, majorVer);
if(::WSAStartup(sockVersion,&wsaData)!=0){exit(0);}
}
~CInitSock(){::WSACleanup();}
};
CInitSock initSock;//初始化Winsock库
int main(){
system("chcp 65001");//更改格式,防止出现中文乱码
// 创建套接字
SOCKET sListen=::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
//用来指定套接字使用的地址格式,通常使用AF_INET
//指定套接字的类型,此处用的是SOCK_DGRAM,表示为udp不可靠传输
//配合type参数使用,指定使用的协议类型(当指定套接字类型后,可以设置为0,因为默认为UDP或TCP)
if(sListen==INVALID_SOCKET){
printf("Failed socket()\n");
return 0;
}
// 填充sockaddr_in结构 ,是个结构体
/* struct sockaddr_in {
short sin_family; //地址族(指定地址格式) ,设为AF_INET
u_short sin_port; //端口号
struct in_addr sin_addr; //IP地址
char sin_zero[8]; //空子节,设为空
} */
sockaddr_in sin;
sin.sin_family=AF_INET;
sin.sin_port=htons(9030);//端口号(1024 ~ 49151)
sin.sin_addr.S_un.S_addr=INADDR_ANY;
// 绑定这个套节字到一个本地地址
if(::bind(sListen,(LPSOCKADDR)&sin,sizeof(sin))==SOCKET_ERROR){
printf("Failed bind()\n");
return 0;
}
// 进入监听模式
//2指的是,监听队列中允许保持的尚未处理的最大连接数
if(::listen(sListen,2)==SOCKET_ERROR){
printf("Failed listen()\n");
return 0;
}
while(TRUE){
sockaddr_in remoteAddr;
int nAddrLen=sizeof(remoteAddr);
SOCKET sClient=0;
// 接受一个新连接
//((SOCKADDR*)&remoteAddr)一个指向sockaddr_in结构的指针,用于获取对方地址
sClient=::accept(sListen,(SOCKADDR*)&remoteAddr, &nAddrLen);
if(sClient==INVALID_SOCKET){printf("Failed accept()");continue;}
printf("接受到一个连接:%s\r\n",inet_ntoa(remoteAddr.sin_addr));
//从客户端接收数据
char data[300];
int nRecv=::recv(sClient,data,300,0);//从socket缓存读取数据,300为接收数据字节上限,返回值为接收数据字节数
if(nRecv>0){
data[nRecv]='\0';
printf("接收到数据:%s\n",data);
}
/*
...
处理数据
*/
// 向客户端发送数据
::send(sClient,data,strlen(data),0);
// 关闭同客户端的连接
::closesocket(sClient);
}
// // 关闭监听套节字
// ::closesocket(sListen);
return 0;
}
注意C++文件在编译时(Windows系统下)加上 -lwsock32 指令,表示 链接到WS2_32.lib动态库,其是Windows Sockets应用程序接口
由于Windows系统在编码等方面存在诸多问题,所以建议还是在linux系统下编译
总体概括为:
C++文件中创建一个socket,并找一个端口进行监听(listen);
php文件中创建一个socket,并对该端口开始一个socket连接(connect);
C++文件中的socket接受该socket连接(accept);
php文件把数据写到socket缓存中(write);
C++文件从socket缓存处读取文件(recv);
C++文件把数据发出(send);
php文件读取数据(read);
详见 https://blog.csdn.net/dlutbrucezhang/article/details/8577810 和 https://blog.csdn.net/weixin_35253106/article/details/115316408
Step5 json格式传递
C++通过socket传回字符串到php文件
考虑如何将php文件中得到的字符串转化成json格式
php
$tmp_arr=explode(" ",$res);//按" "将字符串res分离,放入数组tmp_arr中
$arr=array('startstation'=>$tmp_arr[0],'startdate'=>$tmp_arr[1],'starttime'=>$tmp_arr[2],'endstation'=>$tmp_arr[4],'enddate'=>$tmp_arr[5],'endtime'=>$tmp_arr[6]);
echo json_encode($arr);//将数组编码成json格式传回
上述js中接收到的是json格式的字符串
考虑如何在js中把json格式的字符串转成json类型并考虑进行字符串输出
var str=xmlhttp.responseText;
var data=eval("("+str+")");//eval函数将字符串类型的json数据转化成json类型
var ans=JSON.stringify(data.startstation);//JSON.stringify()可将json类型转化成字符串类型的json数据
ans=ans.substring(1,ans.length-1);//去除头尾两个双引号
document.getElementById("ShowPassword").innerHTML=ans;//在具体位置显示
总结
通过上述操作,我们便可实现
前端(网页 .html/css/js)——网页服务器(后端 .php)——逻辑服务器(后端 C++)——数据库(后端)
首先通过 nginx开放端口,我们可以实现html/js文件与php文件的数据交互,再使用Ajax的方法,我们可以实现 在不重新加载整个页面的前提下更改页面信息
接着通过socket,我们可以实现php文件和C++的数据交互
而最后的数据库和C++可以手写B+tree作为数据库进行交互