所有分类
  • 所有分类
  • 游戏源码
  • 网站源码
  • 单机游戏
  • 游戏素材
  • 搭建教程
  • 精品工具

PHP实现简单HTTP服务器|超详细新手实战教程|快速搭建运行

PHP实现简单HTTP服务器|超详细新手实战教程|快速搭建运行 一

文章目录CloseOpen

第一步:先搞懂HTTP服务器的底层逻辑——其实就3步

在写代码之前,你得先明白:HTTP服务器的核心,其实就是“和浏览器对话”的逻辑。我当时被“服务器”这三个字吓住,后来朋友用快递柜打比方,一下就懂了——你可以把HTTP服务器想成小区门口的快递柜:

  • 接收请求:浏览器(用户)把“要拿什么快递”(请求内容)通过网络传给服务器;
  • 处理请求:服务器“检查快递单”(解析请求里的路径、方法),找到对应的“快递”(资源);
  • 返回响应:服务器把“快递”(HTML/JSON等内容)包装好,还给浏览器。
  • 而PHP做这个的关键,就是用Socket扩展来当“快递柜的通信线路”。我当时一开始没搞懂Socket是啥,直接复制代码,结果运行报错“Call to undefined function socket_create()”——后来才知道,得先去php.ini里把extension=socket前面的分号去掉,开启Socket扩展(像给PHP装个“电话卡”,才能和浏览器通话)。

    再补个小知识点:为什么选Socket?因为Socket是PHP最基础的网络通信工具,不用依赖任何框架,能帮你直接理解“服务器和浏览器怎么说话”。就像学骑自行车,先骑没有辅助轮的,学会了再骑带辅助轮的——等你搞懂Socket版的服务器,再学Nginx、Apache这些高级服务器,就会觉得“哦,原来它们的底层也是这套逻辑”。

    第二步:写代码——从0到1搭建服务器的具体操作

    接下来直接上干货,我把当时的代码拆成“4个模块”,你跟着复制就行,每一步我都标了“坑点”,帮你避坑。

    模块1:先搭Socket的“基础通信线路”

    你得创建一个server.php文件,先写“装电话、占线、接电话”的代码——这是服务器能运行的基础:

    // 
  • 创建Socket(装电话):用IPv4、TCP协议
  • $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);

    if (!$socket) {

    die('Socket创建失败:' . socket_strerror(socket_last_error()));

    }

    //

  • 绑定IP和端口(占线):127.0.0.1是本地地址,8000是端口(别用80,容易被占用)
  • $result = socket_bind($socket, '127.0.0.1', 8000);

    if (!$result) {

    die('绑定失败:' . socket_strerror(socket_last_error()));

    }

    //

  • 监听端口(等电话):最多允许10个等待连接(不用改)
  • $result = socket_listen($socket, 10);

    if (!$result) {

    die('监听失败:' . socket_strerror(socket_last_error()));

    }

    echo "服务器已启动,地址:http://127.0.0.1:8000n";

    坑点提醒:我当时第一次运行这个代码,报错“Permission denied”(权限不够),后来才知道——Linux/Mac下用1024以下的端口需要root权限,所以直接用8000、8080这种“高位端口”就行,省得麻烦。

    模块2:加“循环接受请求”——让服务器一直“在线”

    刚才的代码只能“接一次电话”,浏览器刷新页面就会断。所以得加个while(true)循环,让服务器一直等新的请求:

    // 
  • 循环接受连接(一直等电话)
  • while (true) {

    // 接受客户端连接(接电话):这个函数会“卡住”,直到有浏览器连进来

    $client = socket_accept($socket);

    if (!$client) {

    echo '连接失败:' . socket_strerror(socket_last_error()) . "n";

    continue;

    }

    // 读取浏览器发的请求(听用户说什么):1024是最多读1024字节

    $request = socket_read($client, 1024);

    if (!$request) {

    socket_close($client);

    continue;

    }

    // 这里后面加“处理请求”的代码

    }

    为什么要循环? 因为HTTP是“无状态”的——每个请求都是独立的,服务器处理完一个请求,得赶紧回到“等电话”的状态,不然下一个请求就找不到它了。我当时没加循环,第一次访问成功,刷新就报错“无法连接”,后来加了循环才解决。

    模块3:解析请求——听懂浏览器“要什么”

    浏览器发过来的请求是一堆字符串,比如:

    GET /index.html HTTP/1.1rn
    

    Host: 127.0.0.1:8000rn

    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...rn

    你得从中拆出关键信息:请求方法(比如GET)、请求路径(比如/index.html)。我当时用最笨但有效的方法——用explode拆分字符串:

    // 解析请求行:请求的第一行是“方法 路径 协议”,比如“GET /index.html HTTP/1.1”
    

    $requestLines = explode("rn", $request);

    $requestLine = $requestLines[0]; // 取第一行

    list($method, $path, $protocol) = explode(' ', $requestLine);

    // 打印请求信息(方便调试)

    echo "收到请求:方法=$method,路径=$pathn";

    坑点提醒:如果浏览器发的是POST请求,请求体在rnrn后面,比如表单提交的数据,这时候得用socket_read多读一次——我当时试POST请求,结果只拿到请求头,没拿到请求体,后来查资料才知道,POST的请求体是在请求头之后的,得判断$request里有没有rnrn,再拆分。

    模块4:构造响应——给浏览器“想要的东西”

    解析完请求,接下来要给浏览器返回内容。HTTP响应得严格按照“状态行→响应头→空行→响应体”的顺序来,不然浏览器会“听不懂”。我当时写的第一个响应是这样的:

    // 
  • 状态行:HTTP/1.1是协议版本,200是“成功”状态码,OK是描述
  • $statusLine = "HTTP/1.1 200 OKrn";

    //

  • 响应头:告诉浏览器“返回的是HTML”,编码是UTF-8
  • $headers = "Content-Type: text/html; charset=utf-8rn";

    $headers .= "Connection: closern"; // 处理完请求就断开连接

    //

  • 空行:必须有,用来分隔响应头和响应体
  • $blankLine = "rn";

    //

  • 响应体:你要显示的内容,比如HTML
  • $body = "

    我的PHP服务器";

    $body .= "

    成功啦!这是PHP服务器返回的内容~

    ";

    $body .= "

    你请求的路径是:$path

    ";

    $body .= "";

    // 把响应拼起来

    $response = $statusLine . $headers . $blankLine . $body;

    // 给浏览器发响应(挂电话前把快递给用户)

    socket_write($client, $response);

    // 关闭客户端连接(挂电话)

    socket_close($client);

    关键提醒
  • 响应头里的Content-Type一定要对——如果返回JSON,就写application/json;返回图片,就写image/jpeg,不然浏览器会乱显示(比如我之前返回JSON没改Content-Type,结果浏览器显示成纯文本,全是大括号);
  • 空行不能少——rnrn是HTTP协议的“分隔符”,少了这个,浏览器会认为响应头还没结束,一直等,最后超时。
  • 第三步:运行和调试——解决你大概率会遇到的3个坑

    代码写好了,接下来运行试试。打开命令行,进入server.php所在的文件夹,输入php server.php,然后打开浏览器,输入http://127.0.0.1:8000——如果看到你写的HTML内容,就说明成了!要是没成功,大概率是以下3个坑:

    坑1:端口被占用

    症状:运行代码报错“socket_bind() failed: Address already in use”。

    解决办法:

  • Windows:打开命令行,输入netstat -ano | findstr 8000(8000是你用的端口),找到占用端口的进程ID(最后一列),然后用taskkill /pid 进程ID /f杀掉;
  • Linux/Mac:输入lsof -i 8000,找到进程ID,用kill -9 进程ID杀掉。
  • 坑2:Socket扩展没开

    症状:报错“Call to undefined function socket_create()”。

    解决办法:找到php.ini文件(可以用php ini命令查位置),打开后找到extension=socket,把前面的分号去掉,保存后重启命令行。

    坑3:响应格式错误

    症状:浏览器显示“无法解析服务器的响应”或“ ERR_INVALID_HTTP_RESPONSE”。

    解决办法:检查响应的结构——是不是有状态行?是不是有响应头?是不是有rnrn空行?我当时第一次写响应,漏了空行,结果浏览器一直转圈,后来加了rnrn就好了。

    最后再给你个“进阶小技巧”:如果想让服务器返回不同的内容(比如访问/about显示关于页面,访问/api返回JSON),可以加个switch判断路径:

    switch ($path) {
    

    case '/about':

    $body = "

    关于我们

    这是用PHP服务器做的关于页面~

    ";

    break;

    case '/api':

    $body = json_encode(['code' => 200, 'msg' => '成功', 'data' => ['name' => 'PHP Server']]);

    $headers = "Content-Type: application/json; charset=utf-8rn"; // 改响应头

    break;

    default:

    $body = "

    404 没找到

    你访问的路径$path不存在~

    ";

    $statusLine = "HTTP/1.1 404 Not Foundrn"; // 改状态码

    break;

    }

    我当时加了这个判断后,访问http://127.0.0.1:8000/api,浏览器直接显示JSON数据,感觉特别有成就感——原来自己写的服务器,真的能处理不同的请求!

    对了,你要是怕记不住状态码,可以存一下这个我整理的常用HTTP状态码表,关键时刻能救急:

    状态码 含义 什么时候用
    200 成功 返回正常内容(比如HTML、JSON)
    404 未找到 请求的路径不存在(比如访问/a/b/c.html)
    500 服务器内部错误 PHP代码写错了(比如语法错误、变量未定义)
    400 请求错误 浏览器发的请求格式不对(比如没有请求行)

    怎么样?是不是没想象中难?你跟着步骤试的时候,要是遇到报错,记得先看命令行里的输出——PHP会把错误信息打出来,比如“Undefined variable: path”就是变量没定义,“socket_write() expects parameter 1 to be resource”就是$client没拿到连接。

    我当时第一次成功运行的时候,盯着浏览器里的“成功啦!”字样,兴奋得截图发了朋友圈——原来所谓的“服务器”,也不过是一堆按规则写的代码而已。你要是试成功了,欢迎在评论区告诉我,我帮你看看能不能再加个“静态文件处理”(比如返回CSS、JS文件)的功能~


    你肯定遇到过这种情况——服务器返回的HTML页面光秃秃的,想加个CSS让标题变红色、加个JS让按钮跳一下,结果链接了.css或.js文件后,要么浏览器显示“无法加载资源”,要么页面压根没变化。其实要让PHP服务器返回静态文件,核心就两件事:把文件内容“读出来”,再“明确告诉浏览器这是什么类型的文件”。我之前第一次试的时候,直接在HTML里写,结果浏览器请求style.css时,服务器还是返回之前的“成功啦”HTML——后来才反应过来,服务器根本没处理静态文件的逻辑,得自己加代码去读文件。比如要返回style.css,得用file_get_contents()函数把style.css里的内容“读”进PHP变量里,就像你打开电脑里的TXT文件看内容一样,PHP得先拿到文件里的代码,才能传给浏览器。

    然后最容易忘但最关键的一步:得让浏览器“认得出”这个文件是CSS还是JS。怎么认?靠响应头里的Content-Type啊!比如CSS文件,你得在响应头里写Content-Type: text/css;JS文件就写application/javascript。我之前犯过超蠢的错:把CSS的Content-Type写成了text/html,结果浏览器把CSS代码当成HTML解析,页面上直接显示一堆body { background: #f0f0f0; }的文字,差点以为服务器崩了,后来改对了才恢复正常。还有啊,文件路径一定要核对清楚!比如你的CSS文件放在server.php同目录的“static”文件夹里,那读文件的路径就得是“static/style.css”,要是写成“statics/style.css”(多了个s)、或者“style.css”(没加static文件夹),服务器找不到文件,就会返回404。我当时调试了半小时,才发现是文件夹名拼错了,拍着脑门骂自己“怎么这么粗心”。


    运行代码时提示“Call to undefined function socket_create()”怎么办?

    这是因为PHP的Socket扩展没开启。解决方法:找到php.ini文件(可通过php ini命令查位置),打开后找到extension=socket这一行,把前面的分号去掉,保存后重启命令行或服务器即可。

    启动服务器时提示“Address already in use”怎么解决?

    这是端口被其他程序占用了。Windows系统:用netstat -ano | findstr 端口号找到占用进程ID,再用taskkill /pid 进程ID /f杀掉;Linux/Mac系统:用lsof -i 端口号找到进程ID,再用kill -9 进程ID结束进程,之后重新启动服务器。

    浏览器显示“无法解析服务器响应”或“ERR_INVALID_HTTP_RESPONSE”怎么办?

    大概率是响应格式错了。检查这四点:①有没有状态行(如HTTP/1.1 200 OK);②响应头有没有写对Content-Type(比如HTML用text/html,JSON用application/json);③响应头和响应体之间有没有加rnrn空行;④响应内容有没有语法错误(比如HTML标签没闭合)。

    这个PHP服务器能处理POST请求吗?需要怎么改?

    可以处理。POST请求的请求体在rnrn后面,需要先拆分请求内容:用explode("rnrn", $request)把请求分成“请求头”和“请求体”两部分,第二部分就是POST的数据(比如表单提交的username=test&password=123)。之后用parse_str()函数解析成数组,就能拿到POST参数了。

    怎么让服务器返回CSS、JS这类静态文件?

    需要先读取文件内容,再设置正确的Content-Type。比如返回CSS文件:①用file_get_contents()读取.css文件的内容;②响应头里的Content-Type改成text/css;③把读取的内容作为响应体返回。JS文件同理,Content-Type用application/javascript即可。注意要确保文件路径正确,避免404错误。

    原文链接:https://www.mayiym.com/46343.html,转载请注明出处。
    0
    显示验证码
    没有账号?注册  忘记密码?

    社交账号快速登录

    微信扫一扫关注
    如已关注,请回复“登录”二字获取验证码