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中写的对上)

(不能把运行它的命令行关掉)

  1. 测试是否成功
    在网页根目录下添加 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>密&emsp;码: </label><input name="password" type="password"><br>

        <!-- 下拉菜单控件 -->
        <label>性&emsp;别:</label>
        <select name="sex">
            <option value="1">男</option>
            <option value="2">女</option>
            <option value="3">未知</option>
        </select>
        <br>

        <!-- 复选框控件 -->
        <label>爱&emsp;好:</label>
        <input type="checkbox" name="hobby" value="1">听音乐
        <input type="checkbox" name="hobby" value="2">看电影
        <input type="checkbox" name="hobby" value="3">打游戏
        <br>

        <!-- 单选按钮控件 -->
        <label>学&emsp;历:</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="提 交">&emsp;&emsp;
        <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/8577810https://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作为数据库进行交互

posted @ 2022-04-21 23:02  zhongzero  阅读(43)  评论(0编辑  收藏  举报