服务端网络编程知识框架

进程的基础知识

线程基础知识

协程基础知识

进程线程协程的对比- 多任务:进程、线程与协程

Socket

unix socket tcp socket

五种 I/O 模型

阻塞 I/O

非阻塞 I/O

I/O 的多路复用(select 和 poll)

信号驱动的 I/O(SIGIO)

异步 I/O(POSIX 的 aio_functions)

Reactor模型

TCP粘包

[网络坦白局] TCP粘包 数据包:我只是犯了每个数据包都会犯的错 |硬核图解

惊群效应

网络通讯协议

Linux inotify

C10k问题

C10k文档

Libevent

event loop 事件循环

C/S 客户端->服务端 编程模型

Guzzle使用经验总结

中文文档 英文文档

调用接口

主要功能,很多sdk都是使用该类库开发

写爬虫抓取页面

Laravel 下使用 Guzzle 编写多线程爬虫实战

项目中应用案例

java的古籍PC网站,该项目无人维护,无法提供书籍数据的接口。分析页面结构和接口使用guzzle库爬取书籍数据,完成数据对接。

在所用请求中共享cookie功能 文档

//创建客户端
$this->client = new Client([
    'base_uri' => $this->config['base_uri'],
    'timeout'  => 20.0,
    'cookies' => true, //共享cookie会话
);
//登录
protected function login()
{
    $response = $this->client->request('POST', 'XXX', [
            'headers' => [
                'Accept' => 'application/json'
            ],
            'form_params' => [
                'loginName' => $this->config['login_name'],
                'loginPassword' => $this->config['login_password']
            ]
        ]);

        $json = json_decode($response->getBody(), true);

        if (isset($json['operateMsg']) && $json['operateMsg'] !== '登录成功!') {
            throw new GujiException('原古籍系统账号故障');
        }
}

//请求接口数据
protected function request(string $pathUrl, array $param)
{
        $this->login(); //首先登录获取Cookies
        $response = $this->client->request('POST', $pathUrl, [
            'headers' => [
                'Accept' => 'application/json'
            ],
            'form_params' => $param
        ]);

        $contents = $response->getBody()->getContents();
        $json = json_decode($contents, true);

        if (json_last_error() === JSON_ERROR_NONE) {
            return $json;
        } elseif (json_last_error() == 10) {
            //解决json_decode错误Single unpaired UTF-16 surrogate in unicode escape
            $contents = \preg_replace('/(?<!\\\)\\\u[a-f0-9]{4}/iu', '', $contents);
            $json = \json_decode($contents, true);

            if (json_last_error() !== JSON_ERROR_NONE) {
                $json = $this->customJsonDecode($contents);
            }

            return $json;
        }
        {
            throw new GujiException("请求古籍系统接口失败");
        }
}

//抓取页面数据
protected function capture(string $pathUrl, array $param = [])
{
        $this->login(); //首先登录获取Cookies
        $response = $this->client->request('GET', $pathUrl, $param);

        if ($response->getStatusCode() == 200) {
            //获取页面内容
            return $response->getBody()->getContents();
        } else {
            throw new GujiException("古籍系统故障");
        }
}

跟随重定向

https://docs.guzzlephp.org/en/stable/faq.html#how-can-i-track-redirected-requests

https://docs.guzzlephp.org/en/stable/request-options.html#allow-redirects

调用非知名第三方支付系统,前后端分离架构,前端重定向到接口,接口调用第三方支付接口,成功后跟随响应到成功页面

use Illuminate\Support\Facades\Http;
use Psr\Http\Message\UriInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

//Http::withOptions laravel对guzzle的封装,详情看文档
$response = Http::withOptions([
            'allow_redirects' => [
                'max'             => 1,
                'on_redirect'     => function (
                    RequestInterface $request,
                    ResponseInterface $response,
                    UriInterface $uri
                ) use ($data) {

                    //自动跟随重定向响应
                    header('Location:' . $uri);
                },
            ]
        ])->asForm()->post($this->config['base_uri'] . '/multipay/h5.do', $data);

Linux日志管理

日志目录
/var/log/message 系统启动后的信息和错误日志,是Red Hat Linux中最常用的日志之一
/var/log/secure 与安全相关的日志信息
/var/log/maillog 与邮件相关的日志信息
/var/log/cron 与定时任务相关的日志信息
/var/log/spooler 与UUCP和news设备相关的日志信息
/var/log/boot.log 守护进程启动和停止相关的日志消息
/var/log/wtmp 该日志文件永久记录每个用户登录、注销及系统的启动、停机的事件
/var/log/yum.log
/var/log/syslog
/var/log/dmesg
/var/log/journal

history 显示或操作历史列表 文档

more 显示文件内容,每次显示一屏 文档

  • 按 Space 键:显示文本的下一屏内容。
  • 按 Enter 键:只显示文本的下一行内容。
  • 按斜线符|:接着输入一个模式,可以在文本中寻找下一个相匹配的模式。
  • 按H键:显示帮助屏,该屏上有相关的帮助信息。
  • 按B键:显示上一屏内容。
  • 按Q键:退出more命令。

less 分屏上下翻页浏览文件内容 文档

  • PageUp键向上翻页
  • PageDown键向下翻页
  • Q键退出

tail 在屏幕上显示指定文件的末尾若干行 文档

#查看指定ip的nginx日志
tail -f /dir_name/access.log | grep xxx.xxx.xxx.xxx

sudo journalctl -xe 查看systemd 错误日志 journalctl

参考

linux 6中日志参考方法

Linux 系统日志查看分析(Rsyslog)

Shell常用语法和案例

awesome-shell

ag – 通过目录层次结构,快速搜索文本

shell大全

网道Bash基础教程

Linux shell 中$() ` `,${},$[] $(()),[ ] (( )) [[ ]]作用与区别

获取时间到变量

currentdate=$(date +%Y%m%d)

字符串操作

向文件末尾追加多行文本

here文档语法

Here 文档内部会发生变量替换,同时支持反斜杠转义,但是不支持通配符扩展,双引号和单引号也失去语法作用,变成了普通字符。

cat >> 1.txt <<EOF
export NVM_DIR="\$HOME/.nvm"
[ -s "\$NVM_DIR/nvm.sh" ] && \. "\$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "\$NVM_DIR/bash_completion" ] && \. "\$NVM_DIR/bash_completion"  # This loads nvm bash_completion
EOF

使用指定用户运行命令

sudo -u username command
su -c "cd /www/wwwroot/tuntun/server_php && /www/server/php/74/bin/php artisan schedule:run >> /dev/null 2>&1" -s /bin/sh www

文本操作

sed 替换文本

linux中sed命令替换包含引号、斜杠等特殊字符的的使用

Shell中使用grep、sed正则提取和替换字符串

Shell判断字符串包含关系的几种方法

应用场景描述

安装nvm脚本时需要添加环境变量,卸载时又想把环境变量删除。可以在写入时,在文件末尾追加特殊标识,删除时通过sed删除末尾有标识行

#写入时增加##nvm标识
cat >> /home/${run_user}/.bashrc <<EOF
export NVM_DIR="\$HOME/.nvm"##nvm
[ -s "\$NVM_DIR/nvm.sh" ] && \. "\$NVM_DIR/nvm.sh"##nvm
[ -s "\$NVM_DIR/bash_completion" ] && \. "\$NVM_DIR/bash_completion"##nvm
EOF

#删除末尾有##nvm的行,通过元字符$匹配
sed -i '/##nvm$/d' .bashrc

获取系统信息

查看Linux内核版本

#方式一
cat /proc/version
Linux version 5.13.0-51-generic (buildd@lcy02-amd64-046) (gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0, GNU ld (GNU Binutils for Ubuntu) 2.34) #58~20.04.1-Ubuntu SMP Tue Jun 14 11:29:12 UTC 2022

#方式二
uname -a
Linux MINIPC-PN51-E1 5.13.0-51-generic #58~20.04.1-Ubuntu SMP Tue Jun 14 11:29:12 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux

查看Linux发行版相关信息

#方式一
lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 20.04.4 LTS
Release:	20.04
Codename:	focal

#方式二
cat /etc/issue
Ubuntu 20.04.4 LTS

#仅适合Redhat系的Linux
cat /etc/redhat-release

输入输出重定向

Shell 输入/输出重定向

Linux shell中2>&1的含义解释 (全网最全,看完就懂)

数组常用操作

#读取目录下名字为php*的目录,存为数组, 然后合并数组
enable_dir=(`find /usr/local/php/etc/php.d -maxdepth 1 -type f -name "*.ini" | sort`)
disable_dir=(`find /usr/local/php/etc/php.d/disable -maxdepth 1 -type f -name "*.ini" | sort`)
extension_dir=(${enable_dir[@]} ${disable_dir[@]})

条件语句

Shell脚本IF条件判断和判断条件总结

Composer使用经验总结

切换国内镜像 composer 加速扩展包—— hirak/prestissimo 中文文档

–ignore-platform-reqs:  忽略 phphhvmlib-* 和 ext-* 要求并强制安装,就算本地环境不完全要求。平台配置选项可见 platform 文档

举例说明,windows平台的php不支持pcntl扩展,安装laravel-horizon时需要用的该扩展,可以通过指令强制安装

–with-all-dependencies:(-W)

 添加所有白名单中的依赖到白名单,包括那些根依赖,

允许升级、降级和删除目前锁定在特定版本的软件包。

composer require packagename:*

不确定当前项目可以使用扩展的哪个版本的时,可以使用require xxx:* 来计算是否有任何版本可以安装

laravel5.5安装horizon示例

依赖冲突

比如package A 和 B依赖相同的package C,但是版本不同,需要通过github 或packagelist 的composer.json 找到A和B依赖的最低版本C然后卸载C 然后安装适合版本的A和B,这样会自动安装最适合版本C

laravel 如何覆盖composer的 vendor类文件? 适用于需要修改vendor代码的场景

项目和框架运行缓慢

基于composer构建的项目出现过,加载运行缓慢的问题。碰到过旧laravel项目运行php artisan -v 时,命令显示非常慢。运行php artisan server 访问页面响应也很慢。

具体原因未验证,可能是安装依赖时,和运行项目时的php版本不一致,使用低版本安装了依赖,切换了高版本的php。composer安装项目后,会在vendor/bin目录下生成命令文件和缓存之类的,

解决方法,将vendor目录完全删除,然后重新运行composer install ,项目在升级或切换composer版本和php版本之后保险起见需要重新安装依赖

引入本地包

laravel-devstart 本地包的名称,path指定目录 要用基于当前项目路的相对路径,适用于开发扩展包

//设置路径,本质是创建了一个系统软连接
composer config repositories.laravel-devstart path ../../package/laravel-devstart
//引入本地包的master分支
composer require yangliuan/laravel-devstart:dev-master

扩展包开发

安装 Package Builder 包结构创建工具
composer global require overtrue/package-builder 
安装项目需要的依赖

修改composer.json

编写异常

编写单元测试

测试扩展包

发布版本到github

发布第一个版本

自动化测试

使用 GitHub Actions 做自动化测试

使用 StyleCI 自动修复代码格式

参考教程

LX2 PHP 扩展包实战教程 – 从入门到发布

PHP回顾之创建自己的扩展包 概述

扩展包版本对应

Laravel旧版本和扩展包对应版本,方便维护旧项目时参考

Laravel版本扩展包版本
5.5“laravel/horizon”: “2.1”
5.5“barryvdh/laravel-ide-helper”: “2.4.1”
5.5“doctrine/dbal”: “^2.10”
5.5“laravel/passport”: “~4.0”
5.5“laravel/tinker”: “~1.0”
5.5“propaganistas/laravel-phone”: “^4.2”
5.5“barryvdh/laravel-debugbar”: “3.4”,
5.5“filp/whoops”: “~2.0”
5.5“friendsofphp/php-cs-fixer”: “^2.14” 配置文件为.php_cs.dist

Linux文件系统 FAQ

rm cannot remove xxx Read-only file system 无法删除文件

df dir 查看无法删除的目录所在的文件系统

df /snap/remmina/
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/nvme0n1p2 479152840 195515620 259227828 43% /

fsck -y /   #执行修复文件系统 的挂载根目录 或者 有问题的文件所在的挂载目录;

shutdown -r now

再删除ubuntu系统中的snap应用文件时上述方法没有解决

使用df -h 查看 发现remmina中的 /snap/remmina/4978 的挂载点是/dev/loop12

sudo umount /dev/loop12 去掉挂载后,再删除就可以了 ,原因是磁盘的挂载目录无法直接被删除

阿里云在线扩容磁盘遇到的问题

按照官方文档扩容

输入growpart 命令时 没有查找一下该命令的参数和含义,照着文档以为是截图中的序号,结果报如下错误

NOCHANGE: partition 2 is size 0. it cannot be grown

growpart <DeviceName> <PartionNumber>

应该输入分区好,即截图中1,/dev/vdb 是设备名称 ,/dev/vdb1是设备名称+分区号,即设备分区

总结:
服务器运行不了解的命令一定要先查一下文档手册,看个大概,梳理一下操作的大概意思,然后在操作
完善一下文件系统的文档,复习一下文件系统的知识

参考

在线扩容云盘(Linux系统)

阿里云Linux服务器动态扩容(阿里云服务器扩容后磁盘空间无变化解决方法)

Linux安装PHP FAQ

离线安装

很多国企和大型企业的自建机房不允许访问公网,流量只能进开发固定端口,造成安装LNMP环境时缺少各种依赖和报错。以centos系统为例

1.上传和服务器版本一致的操作系统镜像,(例:CentOS-7-x86_64-Everything-2009.iso,一定要使用everything版本包含软件包) 到服务器

2.挂载光盘镜像

mkdir /mnt/dvd //创建挂载目录
mount -o loop /xxx/CentOS-7-x86_64-Everything-2009.iso /mnt/dvd  //挂载,xxx为镜像所在目录
df -h  //查看 /mnt/dvd 挂载点是否挂载成功

3.配置yum本地源

mkdir /etc/yum.repos.d/bk //创建备份目录
mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/bk //备份源文件

vim /etc/yum.repos.d/CentOS-Media.repo  //编辑本地源
//centos6/7内容如下,file路径为上一步的镜像挂载
[local-media]
name=CentOS-$releasever-Media
baseurl=file:///mnt/dvd/
gpgcheck=1
enabled=1
gpgkey=file:///mnt/dvd/RPM-GPG-KEY-CentOS-7

//CentOS 8本地源配置文件写法与CentOS6和7不同,配置文件内容如下:
[LocalRepo_BaseOS]
name=LocalRepository_BaseOS
baseurl=file:///mnt/dvd/BaseOS
enabled=1
gpgcheck=0

[LocalRepo_AppStream]
name=LocalRepository_AppStream
baseurl=file:///mnt/dvd/AppStream
enabled=1
gpgcheck=0

//保存然后执行
yum clean all && yum makecache

//测试一下是否可用
yum install git

4 执行离线安装

使用oneinstack

一台服务器(可以使用系统版本系统的虚拟机替代)联网使用oneinstack安装后,src目录里会有相应的包,打包oneinstack 放到需要离线安装的服务器(配置好内网yum源)就是离线了。

使用lnmp一键安装包,需要下载完整包

执行CheckMirror=n ./install.sh lnmp

5 其它参考

https://blog.51cto.com/u_1836630/2417675

Linux编译安装相关知识

linux查看某个库是否安装

https://blog.csdn.net/vantian/article/details/76636327

ldconfig -p | grep pcap