[置顶] PID算法C源代码

WEB2.0 jackxiang 2010-6-16 10:31
远程桌面连接linux服务器时,画面突然放大,且画面随光标移动。
解决方法
Alt + 鼠标滑轮
Alt + 鼠标滑轮可以进行画面的放大、缩小。有的时候不注意按到键盘,可能出现这种情况。特此记录。
摘自:https://blog.csdn.net/ykwjt/article/details/127451351

macbook下面是option+鼠标滑轮(苹果鼠标二手指前后移动=远程屏幕放大缩小)
方正小标宋_GBK 二号 的间距如下:
间距:
    段前:0行   行距:固定值 设置值:27磅
    段后:0行


刚好实现此行没有多余的上下位置(鼠标选中后字的上下有占位)。
如下对比图,左边选中就有:
点击在新窗口中浏览此图片

正文一般:字体:仿宋_GB2312 三号
间距:单倍行距,对齐方式:左对齐。
         [V]定义文档网格时对齐网格
缩进:
    左侧:0字符   特殊格式:首行  磅值:2字符
    右侧:0字符

上面就是在写述职报告时会在前面留下两个字符的空格设置(特殊格式:首行  磅值:2字符)。

如下:
点击在新窗口中浏览此图片

1.布局:
切换到 Side By Side Layout,这个布局,更方便操作。
点击在新窗口中浏览此图片
界面主要包括:正则表达式、测试文本、输出结果、历史记录、Create相关面板,见上图。

2.List All:输出结果面板,显示的显示了正则表达式的匹配结果。你可以通过List All切换显示的效果,如下图所示:
点击在新窗口中浏览此图片
可以选中List ALL Group Matches in columns显示的效果,就是上面图中的输出结果面板效果。如果,你选中了Update Automatically,则修改正则或文本内容时候,输出结果面板会实时跟着变化。

3.高亮:
点:Highlight,打开高亮。

4.Debug:
点击 Debug按钮,会自动跳到Debug面板,显示出正则表达式匹配的规则。通过该结果,你可以很直观的分析出正则匹配的过程,如下图所示:
点击在新窗口中浏览此图片

5.一行还是多行匹配:
测试文本面板(Test标签)输入需要测试的文本内容,如:。可以选择Line By Line、Whole File、Page By Page,来指定是每行抽取,还是对整个文档抓取等(如果你的正则匹配信息有包含多行内容,务必要选中Whole File或者Page By Page)。

来自:https://jingyan.baidu.com/article/63acb44a2d9c7761fcc17ebd.html
正则工具:https://regex101.com/
iOS 系统自带的“相机”应用无法进行删除,也就是说正常情况下不会丢失该功能。如果您无法在 iPhone 桌面上找到“相机”应用,可以从资源库中找到并移回至桌面,或检查“屏幕使用时间”设置。

  1.打开资源库查找“相机”:

  在 iPhone 桌面上连续向左轻扫,直至看到“应用资源库”,在资源库中找到“相机”图标,长按拖回到桌面,放置到理想的位置即可。

来自:https://g.pconline.com.cn/x/1585/15859231.html
捕获组与非捕获组概念:https://segmentfault.com/a/1190000021043947
文章中的工具用的正则表达式公式: https://regex101.com/
非捕获部分:(?:.*?<span title="(.*?)" .*?<\/span>)?




对天气中的温度和风力有时间只有一个温度和风力的情况的判断算法:
温度部分:
    $temperature = '';
    if (preg_match('/<span>(.*?)<\/span>\/<i>(.*?)<\/i>/', $matches[4], $temp_matches)) {
        $temperature = $temp_matches[1] . '/' . $temp_matches[2];
    } else if (preg_match('/<i>(.*?)<\/i>/', $matches[4], $temp_matches)) {
        $temperature = $temp_matches[1];
    }

风力部分:
问ChatGPT:我只想知道正则如何匹配到下面这段的:

<p class="win">
<em>
<span title="南风" class="S"></span>
<span title="南风" class="S"></span>
</em>
<i>&lt;3级</i>
</p>
对下面这段正则作下解释:

<p class="win">.*?<span title="(.*?)" .*?<\/span>(?:.*?<span title="(.*?)" .*?<\/span>)?
上面第一个.*?是非贪婪匹配它后面的:<span title=。
上在第二个(.*?)是匹配南风。
上在第三个.*?是非贪婪匹配它后面的:<\/span>。
是对的吧?
二、最想知道的是:
(?:.?<span title="(.?)" .?</span>)?
上在这段正则里面的:?:.? 是想干嘛的呢?
它最后的问号是用来匹配0次或1次用的,这个是这么理解吧。

ChatGPT回答如下:
你说得基本是对的。让我逐步解释一下你提到的正则表达式是如何匹配 `<p class="win">` 这段 HTML 代码的,以及 `(?:.*?<span title="(.*?)" .*?<\/span>)?` 这部分正则表达式的具体作用。

### 1. 正则表达式整体

```regex
<p class="win">.*?<span title="(.*?)" .*?<\/span>(?:.*?<span title="(.*?)" .*?<\/span>)?
```

#### 1.1. `<p class="win">.*?<span title="(.*?)" .*?<\/span>`

- `<p class="win">`: 匹配 `<p>` 标签的开头部分,class 属性为 `win`。
- `.*?`: 非贪婪模式匹配任意字符,尽量少的字符,直到遇到 `<span title=`。
- `<span title="(.*?)"`: 匹配第一个 `span` 标签,并捕获 `title` 属性的值。`(.*?)` 是一个非贪婪模式的捕获组,匹配 `title` 属性的内容,这里会匹配到 `南风`。
- ` .*?<\/span>`: 非贪婪模式匹配任意字符,直到遇到 `</span>`。

这一部分的正则表达式解释如下:
- `<p class="win">` 精确匹配标签的开始部分。
- `.*?` 尽量少的匹配任意字符,直到遇到 `<span title=`。
- `<span title="(.*?)"` 匹配 `span` 标签的 `title` 属性,捕获组 `(.*?)` 非贪婪模式匹配 `title` 的内容,即 `南风`。
- ` .*?<\/span>` 匹配从 `title` 属性结束到 `</span>` 标签结束的所有字符。

#### 1.2. `(?:.*?<span title="(.*?)" .*?<\/span>)?`

- `(?: ... )`: 非捕获组,匹配括号内的内容,但不捕获它。
- `.*?`: 非贪婪模式匹配任意字符,尽量少的字符,直到遇到 `<span title=`。
- `<span title="(.*?)"`: 匹配第二个 `span` 标签,并捕获 `title` 属性的值。`(.*?)` 是一个非贪婪模式的捕获组,匹配 `title` 属性的内容,这里会匹配到第二个 `南风`。
- ` .*?<\/span>`: 非贪婪模式匹配任意字符,直到遇到 `</span>`。
- `?`: 匹配前面的非捕获组 0 次或 1 次。即这部分是可选的。

这一部分的正则表达式解释如下:
- `(?: ... )` 表示一个非捕获组,不会保存匹配结果。
- `.*?` 尽量少的匹配任意字符,直到遇到 `<span title=`。
- `<span title="(.*?)"` 匹配 `span` 标签的 `title` 属性,捕获组 `(.*?)` 非贪婪模式匹配 `title` 的内容,即第二个 `南风`。
- ` .*?<\/span>` 匹配从 `title` 属性结束到 `</span>` 标签结束的所有字符。
- `?` 表示这个非捕获组是可选的,可以匹配 0 次或 1 次。

### 2. 匹配示例

以你提供的 HTML 代码为例:

```html
<p class="win">
<em>
<span title="南风" class="S"></span>
<span title="南风" class="S"></span>
</em>
<i>&lt;3级</i>
</p>
```

- `<p class="win">`: 匹配 `<p class="win">`。
- `.*?`: 非贪婪模式匹配任意字符,直到遇到 `<span title=`。匹配到 `\n<em>\n`。
- `<span title="(.*?)"`: 匹配 `<span title="南风"` 并捕获 `title` 属性的值 `南风`。
- ` .*?<\/span>`: 匹配 `class="S"></span>\n`。

接下来是可选部分:

- `(?:.*?<span title="(.*?)" .*?<\/span>)?`:
  - `.*?`: 非贪婪模式匹配任意字符,直到遇到 `<span title=`。匹配到 `\n`。
  - `<span title="(.*?)"`: 匹配 `<span title="南风"` 并捕获 `title` 属性的值 `南风`。
  - ` .*?<\/span>`: 匹配 `class="S"></span>\n`。
  - `?`: 表示这个部分是可选的,可以匹配 0 次或 1 次。这次匹配到 1 次。

### 总结

- `<p class="win">.*?<span title="(.*?)" .*?<\/span>`: 匹配 `<p class="win">` 开始标签,直到第一个 `span` 标签的 `title` 属性,并捕获其值。
- `(?:.*?<span title="(.*?)" .*?<\/span>)?`: 匹配从第一个 `span` 标签结束到第二个 `span` 标签结束的内容,并捕获第二个 `span` 标签的 `title` 属性,整个部分是可选的。
- `?` 表示前面的非捕获组是可选的,可以出现 0 次或 1 次。



再对正则知识点细节性问:
(?: ... ) 表示一个非捕获组,不会保存匹配结果。
上面这个是什么意思,请再接合解释下面正则:
(?:.?<span title="(.?)" .*?</span>)?

ChatGPT回答:
好的,让我们详细解释一下 `(?: ... )` 和具体的正则表达式 `(?:.*?<span title="(.*?)" .*?<\/span>)?`。

### 非捕获组 `(?: ... )`

- `(?: ... )` 是一个**非捕获组**,它的作用是将括号内的内容进行分组,但不保存这个组的匹配结果。这和普通的捕获组 `(...)` 不同,普通捕获组会保存匹配结果供后续引用,而非捕获组则不会保存。
- 非捕获组主要用于在需要进行分组但不希望保存匹配结果的情况下,这样可以节省内存,并且在使用正则表达式时不需要担心额外的捕获组会影响捕获组编号。

### 具体的正则表达式 `(?:.*?<span title="(.*?)" .*?<\/span>)?`

#### 分解解释

1. **`(?: ... )`**:
   - 这是一个非捕获组,括号内的内容会被当作一个整体来处理,但不会保存匹配结果。

2. **`.*?`**:
   - 非贪婪模式匹配任意字符,尽量少的字符,直到遇到 `<span title=`。
   - 这里匹配的是从 `<p class="win">` 到第一个 `<span title="...">` 之间的任意字符,包括换行符等。

3. **`<span title="(.*?)"`**:
   - 匹配 `<span title="` 字符串,并捕获 `title` 属性的值。
   - `(.*?)` 是一个非贪婪模式的捕获组,匹配 `title` 属性的内容。例如,`南风`。

4. **` .*?<\/span>`**:
   - 非贪婪模式匹配任意字符,直到遇到 `</span>`。
   - 这里匹配的是从 `title` 属性结束到 `</span>` 标签结束的所有字符。

5. **`(?: ... )?`**:
   - 问号 `?` 表示前面的非捕获组是可选的,可以匹配 0 次或 1 次。
   - 整个非捕获组 `(?: ... )` 是可选的,意味着可以有一个额外的 `span` 标签,或者没有。

#### 具体示例

以你的 HTML 代码为例:

```html
<p class="win">
<em>
<span title="南风" class="S"></span>
<span title="南风" class="S"></span>
</em>
<i>&lt;3级</i>
</p>
```

匹配过程如下:

1. **第一部分** `<p class="win">.*?<span title="(.*?)" .*?<\/span>`:
   - 匹配 `<p class="win">` 开始标签。
   - `.*?` 非贪婪模式匹配任意字符,直到遇到第一个 `<span title=`。
   - 匹配并捕获第一个 `span` 标签的 `title` 属性值 `南风`。
   - 匹配 `</span>` 标签。

2. **第二部分** `(?:.*?<span title="(.*?)" .*?<\/span>)?`:
   - `(?: ... )` 非捕获组,将内容作为整体处理。
   - `.*?` 非贪婪模式匹配任意字符,直到遇到第二个 `<span title=`。
   - 匹配并捕获第二个 `span` 标签的 `title` 属性值 `南风`。
   - 匹配 `</span>` 标签。
   - `?` 表示非捕获组是可选的,可以匹配 0 次或 1 次。

### 完整正则表达式的匹配过程

完整的正则表达式 `(?:.*?<span title="(.*?)" .*?<\/span>)?` 在匹配过程中的作用如下:

1. 从 `<p class="win">` 开始,匹配任意字符直到第一个 `<span title=`。
2. 捕获第一个 `span` 标签的 `title` 属性值。
3. 匹配 `</span>` 标签。
4. 非捕获组 `(?: ... )?` 的内容(可选):
   - 匹配任意字符直到第二个 `<span title=`。
   - 捕获第二个 `span` 标签的 `title` 属性值。
   - 匹配 `</span>` 标签。

这段正则表达式会成功匹配以下内容,并分别捕获两个 `span` 标签的 `title` 属性值:

```html
<p class="win">
<em>
<span title="南风" class="S"></span>
<span title="南风" class="S"></span>
</em>
<i>&lt;3级</i>
</p>
```

结果是捕获两个 `span` 标签的 `title` 属性值 `南风` 和 `南风`。如果只有一个 `span` 标签,那么也能成功匹配,只会捕获第一个 `title` 属性值。

cat haiyangguan.sh
#!/bin/bash

# 获取当前时间戳(毫秒)
current_timestamp=$(($(date +%s%N)/1000000))

# 定义curl命令,使用当前时间戳替换原时间戳
curl_command="curl -H 'Host: ocean.shuziwenlv.com' -H 'content-type: application/json; charset=UTF-8' -H 'User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_5_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.49(0x18003133) NetType/WIFI Language/zh_CN' -H 'Referer: https://servicewechat.com/wx49d59947448fc8a7/40/page-frame.html' --data-binary '{\"header\":{\"userNo\":\"\",\"serviceName\":\"CreateOrder\",\"version\":\"v1.0\",\"token\":\"\",\"cacheTime\":0,\"timestamp\":$current_timestamp},\"body\":\"JTdCJTIyZGF0ZSUyMiUzQSUyMjIwMjQtMDYtMDklMjIlMkMlMjJzdHJhdGVneUlkJTIyJTNBJTIyMTAwMDAwMDI1NyUyMiUyQyUyMnByb2plY3RObyUyMiUzQSUyMjEwMDAwMDA2NjYlMjIlMkMlMjJzdWJQcm9qZWN0Tm8lMjIlM0ExMDAwMDAwNjY2JTJDJTIyb3BlbklkJTIyJTNBJTIyb0NhdTU2NGYzTDluYjRIdGlPN1RfOUd6WGExNCUyMiUyQyUyMmFwcE5vJTIyJTNBJTIyMTAlMjIlMkMlMjJ0aWNrZXRMaXN0JTIyJTNBJTVCJTdCJTIyc3R5bGVObyUyMiUzQSUyMjEwMDAwMDEwMDAlMjIlMkMlMjJjb3VudCUyMiUzQTMlMkMlMjJ0b3VyaXN0TGlzdCUyMiUzQSU1QiU3QiUyMm5hbWUlMjIlM0ElMjIlRTUlQkQlQTYlRTYlOTklOTMlRTglOEIlQjklMjIlMkMlMjJtb2JpbGVObyUyMiUzQSUyMjE4NjEwODE1NzA4JTIyJTJDJTIyY2FyZFR5cGUlMjIlM0ElMjIxMCUyMiUyQyUyMmNhcmRObyUyMiUzQSUyMjE1MjMyNjE5ODUwMTE0MzU4OSUyMiUyQyUyMnNlYXRObyUyMiUzQSUyMiUyMiUyQyUyMnNlYXRtYXBObyUyMiUzQSUyMiUyMiUyQyUyMnRpZHglMjIlM0ExJTdEJTJDJTdCJTIybmFtZSUyMiUzQSUyMiVFNSU5MCU5MSVFNCVCOCU5QyUyMiUyQyUyMm1vYmlsZU5vJTIyJTNBJTIyMTg4MTA3NjUxMDglMjIlMkMlMjJjYXJkVHlwZSUyMiUzQSUyMjEwJTIyJTJDJTIyY2FyZE5vJTIyJTNBJTIyNTAwMjMwMTk4NTEwMDI3MTFYJTIyJTJDJTIyc2VhdE5vJTIyJTNBJTIyJTIyJTJDJTIyc2VhdG1hcE5vJTIyJTNBJTIyJTIyJTJDJTIydGlkeCUyMiUzQTIlN0QlMkMlN0IlMjJuYW1lJTIyJTNBJTIyJUU1JTkwJTkxJUU2JUI1JUE5JUU5JUI4JUEzJTIyJTJDJTIybW9iaWxlTm8lMjIlM0ElMjIxMzI2MDE2ODA4NiUyMiUyQyUyMmNhcmRUeXBlJTIyJTNBJTIyMTAlMjIlMkMlMjJjYXJkTm8lMjIlM0ElMjIxMTAxMTIyMDE5MTAyNDQ2MTklMjIlMkMlMjJzZWF0Tm8lMjIlM0ElMjIlMjIlMkMlMjJzZWF0bWFwTm8lMjIlM0ElMjIlMjIlMkMlMjJ0aWR4JTIyJTNBMyU3RCU1RCU3RCU1RCU3RA==\"}' --compressed 'https://ocean.shuziwenlv.com/MiniProgram/ProcessRequest'"

# 执行curl命令
eval $curl_command


#cat run_haiyangguan.sh




^M  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0^M100  1726  100   244  100  1482    829   5039 --:--:-- --:--:-- --:--:--  5058
{"header":{"status":999,"timecost":19,"msg":"剩余库存不足","serviceName":"CreateOrder","serviceUnavailable":false},"body":""}  % Total    % Received % Xferd  Average Speed   Tim
e    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
^M  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0^M100  1482    0     0  100  1482      0   1225  0:00:01  0:00:01 --:--:--  1225^M100  1798  100
  316  100  1482    156    734  0:00:02  0:00:02 --:--:--   734^M100  1798  100   316  100  1482    156    734  0:00:02  0:00:02 --:--:--   734
{"header":{"status":200,"timecost":1556,"msg":"操作成功","serviceName":"CreateOrder","serviceUnavailable":false},"body":"JTdiJTIybGF1bmNoJTIyJTNhZmFsc2UlMmMlMjJvcmRlck5vJTIyJTNh
JTIyMjAwMDUzNTg5OCUyMiU3ZA=="}  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
^M  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0^M100  1751  100   269  100  1482    535   2948 --:--:-- --:--:-- --:--:--  2946^M100  1751  100
  269  100  1482    534   2946 --:--:-- --:--:-- --:--:--  2946
{"header":{"status":999,"timecost":27,"msg":"证件:152**3589请勿重复预定!","serviceName":"CreateOrder","serviceUnavailable":false},"body":""}  % Total    % Received % Xferd  Aver
age Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
^M  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0^M100  1751  100   269  100  1482    928   5115 --:--:-- --:--:-- --:--:--  5128
{"header":{"status":999,"timecost":18,"msg":"证件:152**3589请勿重复预定!","serviceName":"CreateOrder","serviceUnavailable":false},"body":""}  % Total    % Received % Xferd  Aver
age Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
^M  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0^M100  1751  100   269  100  1482    547   3015 --:--:-- --:--:-- --:--:--  3018
{"header":{"status":999,"timecost":17,"msg":"证件:152**3589请勿重复预定!","serviceName":"CreateOrder","serviceUnavailable":false},"body":""}  % Total    % Received % Xferd  Aver
除开strace外还有一款性能分析工具:
sudo yum install perf
perf record -F max -a -g -- screen -ls

perf record -F max -a -g -- screen -ls
info: Using a maximum frequency rate of 11,000 Hz
There is a screen on:
        16882.abc       (Detached)
1 Socket in /var/run/screen/S-root.

[ perf record: Woken up 14 times to write data ]
[ perf record: Captured and wrote 4.143 MB perf.data (34888 samples) ]
可在不同设备上读取的perf.data 文件. 您可以使用 perf 工具将性能数据记录到 perf.data 文件中,以便在不同的设备上分析。


echo Soft: $(ulimit -Sn)
echo Hard: $(ulimit -Hn)
Soft: 1024000
Hard: 1024000

立即生效的解决办法(重启配置失效):
ulimit -Sn 10000
ulimit -Hn 50000

重启后永久生效实操:
要在 CentOS 7 上永久设置 `ulimit`,您需要修改 `/etc/security/limits.conf` 文件。这个文件允许您设置系统级别的资源限制。您可以按照以下步骤进行修改:

1. 打开终端并以 root 用户身份登录。
2. 使用文本编辑器(如 `vi` 或 `nano`)打开 `/etc/security/limits.conf` 文件:

```bash
sudo vi /etc/security/limits.conf
```

3. 在文件末尾添加以下行:

```
*       soft    nofile  10000
*       hard    nofile  50000
```

这里,`soft` 代表软限制,`hard` 代表硬限制。软限制是系统允许的最大值,超过此限制时会发出警告。硬限制是系统允许的绝对最大值,超过此限制时会导致操作失败。通常情况下,软限制和硬限制是相同的。

4. 保存并关闭文件。在 vi 中,您可以按 `Esc` 键输入 `:wq` 然后按 `Enter` 保存并退出。

5. 重新启动系统或重新登录以使更改生效。

现在 `ulimit` 的设置应该在系统重新启动后生效,并且将永久保持。

fix: Normalize RLIMIT_NOFILE (LimitNOFILE) to sensible defaults:
https://github.com/moby/moby/pull/45534

gnu screen run extremely slow when using 'root' user in container since docker 23.0.1 #45380:
https://github.com/moby/moby/issues/45380


=============================================================

火焰图
on-cpu火焰图可以用于分析cpu是被哪些线程、哪些函数占用的,可以方便的找到热点代码便于后续分析优化。下面我们介绍下火焰图的生成和使用方法。

使用方法
准备FlameGraph工具。
git clone https://github.com/brendangregg/FlameGraph.git
用perf record采集CPU信息。
perf record -e cpu-clock -g  ./perf_test
Ctrl+c结束执行后,在当前目录下会生成采样数据perf.data。

用perf script工具对perf.data进行解析。
perf script -i perf.data &> perf.unfold
将perf.unfold中的符号进行折叠。
./stackcollapse-perf.pl perf.unfold &> perf.folded
最后生成svg图。
./flamegraph.pl perf.folded > perf.svg
perf.svg 用浏览器就可以打开

来自:https://github.com/moby/moby/pull/45534
对于:[实践OK]串口学习之上位机查询模式,下位机arduino采用中断方式读取上位机的指令并crc验证其准确性后读取Tsic506的温度值,再通过CRC校验后经串口发送到上位机。https://jackxiang.com/post/12322/ 这部分串口问题的读取采用select模型的细节分析。

优秀,但最终有一个点仍然想向您探讨一下,上面您给修复后的代码片段中这一外逻辑:
            } else if (num_bytes == 0) {
                // 串口关闭或无数据可读
                perror("Serial port closed or no data available");
                exit(EXIT_FAILURE);
            } else {
                // 读取出错
                perror("Error reading from serial port");
                exit(EXIT_FAILURE);
            }

上面代码子片段中,} else if (num_bytes == 0) {,是在select模型中通知有数据可以读到,我理解至少有一个byte及以上不会是0个byte,它什么样的情况下会出现:num_bytes == 0,再就是这种情况是串口硬件问题还是软件问题,是否可以了也给它一个修复 的机会呢?和select 模型一样:
               if (consecutive_failures >= 5) {
                // 连续失败超过5次,发送错误信息到服务器
                send_error_to_server();
                // 退出程序
                exit(EXIT_FAILURE);
            }  
            continue;

还是必须直接exit(EXIT_FAILURE);更为妥当呢?

二是:
            } else {
                // 读取出错
                perror("Error reading from serial port");
                exit(EXIT_FAILURE);
            }

这部分如果串口读取出错,是否有什么标志位呢,直接放在else中就读取出错,是否有些武断了些,我想要是更谨慎编码,也请给出对应的最后else分支的读取出错的标志判断代码,让这部分代码更加健壮:            } else {
                // 读取出错
                perror("Error reading from serial port");
                exit(EXIT_FAILURE);
            }

,我的两点要求问完了,您可以按条回复解答的同时,给出最终解决后并后的代码,十分感谢 。


回答:
关于您的第一个问题,`num_bytes == 0` 的情况通常表示从串口读取到的字节数为 0,即读取操作没有返回任何数据。这可能是因为串口关闭或者是没有数据可读。如果您认为这种情况是由于串口硬件问题而不是程序逻辑问题导致的,那么直接退出程序可能是更为合适的选择。因此,直接使用 `exit(EXIT_FAILURE)` 可能更为妥当。

对于第二个问题,如果串口读取出错,通常会返回 -1,并将 `errno` 设置为适当的错误代码。您可以根据 `errno` 的值来进一步判断错误的类型。因此,在 `else` 分支中,您可以添加一个针对 `errno` 的判断,以确定错误的具体原因,并根据需要采取相应的措施。

下面是针对您的两个问题的解答和相应的代码修正:

1. 对于 `num_bytes == 0` 的情况,我们直接退出程序,因为没有读取到任何数据,这可能是串口关闭或没有数据可读。

2. 对于读取出错的情况,我们可以根据 `errno` 的值判断错误的具体原因,并据此决定是否退出程序。这样可以使代码更加健壮,能够更好地处理可能的错误情况。

下面是修改后的代码片段:

```c
// 串口读取函数
void read_serial(Config *config) {
    unsigned char buffer[BUFFER_SIZE];
    ssize_t num_bytes;
    int frame_start_detected = 0;
    int recv_index = 0;
    int consecutive_failures = 0; // 记录连续失败的次数
    struct timeval tv;
    fd_set rfds;

    while (1) {
        // 发送查询指令
        send_query(config->serial_fd);
        usleep(150000); // 等待150毫秒

        // 设置超时时间为3秒
        tv.tv_sec = 3;
        tv.tv_usec = 0;
        FD_ZERO(&rfds);
        FD_SET(config->serial_fd, &rfds);

        // 等待串口数据
        int retval = select(config->serial_fd + 1, &rfds, NULL, NULL, &tv);
        if (retval == -1) {
            perror("Error in select");
            exit(EXIT_FAILURE);
        } else if (retval == 0) {
            // 超时,增加连续失败计数器
            consecutive_failures++;
            if (consecutive_failures >= 5) {
                // 连续失败超过5次,发送错误信息到服务器
                send_error_to_server();
                // 退出程序
                exit(EXIT_FAILURE);
            }
            continue;
        } else {
            // 读取串口数据
            num_bytes = read(config->serial_fd, buffer + recv_index, BUFFER_SIZE - recv_index);
            if (num_bytes > 0) {
                // 数据读取成功
                consecutive_failures = 0; // 重置连续失败计数器
                recv_index += num_bytes;
                // 打印接收到的十六进制数据
                printf("\n\nReceived data: ");
                for(int i = 0;i < recv_index; ++i){
                   printf("%02X ",buffer[i]);
                }
                printf("\n");

                // 判断帧头是否检测到
                if (!frame_start_detected) {
                    for (int i = 0; i < recv_index; ++i) {
                        if (buffer[i] == 0xAA) {
                            frame_start_detected = 1;
                            // 移动已接收数据到缓冲区开头
                            memmove(buffer, buffer + i, recv_index - i);
                            recv_index -= i;
                            break;
                        }
                    }
                }
                // 判断是否接收到完整的数据包
                if (frame_start_detected && recv_index >= EXPECTED_PACKET_LENGTH && buffer[recv_index - 1] == 0x55) {
                    // 去除帧头和帧尾后的数据长度
                    int data_length = recv_index - 2;
                    // 进行 CRC 校验,传递数据段给 verifyData 函数
                    if (verifyData(buffer + 1, data_length)) {
                        // 提取温度值并打印
                        float temperature = convertToTemperature(buffer + 1);
                        printf("Temperature: %.1f\n", temperature);
                        // 发送POST请求
                        send_temperature_via_post(temperature);
                    } else {
                        printf("CRC 校验失败\n");
                    }
                    // 清除已处理数据
                    recv_index = 0;
                    frame_start_detected = 0;
                }
            } else if (num_bytes == 0) {
                // 串口关闭或无数据可读
                perror("Serial port closed or no data available");
                exit(EXIT_FAILURE);
            } else {
                // 读取出错
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    // 数据暂时不可用,继续下一次循环
                    continue

;
                } else {
                    perror("Error reading from serial port");
                    exit(EXIT_FAILURE);
                }
            }
        }
    }
}
```

这样,当 `num_bytes == 0` 时,表示读取操作未返回任何数据,直接退出程序;当读取出错时,我们根据 `errno` 的值判断错误类型,如果是暂时不可用的错误(如 `EAGAIN` 或 `EWOULDBLOCK`),则继续下一次循环;否则,打印错误信息并退出程序。


细节追问:
很专业,您所回答的:
对于 num_bytes == 0 的情况,我们直接退出程序,因为没有读取到任何数据,这可能是串口关闭或没有数据可读。

这一句中,串口关闭可以理解,如下位机在select明明有数据上来了但这一瞬间串口关掉了,没有读取到任何数据。 但是除开这个特殊情况外还有其它情况吗?我理解明明select 侦测到有数据来了,那么这个数据肯定是num_bytes >= 1,怎么就出现明明就通知有数据就读取到0个数据的逻辑判断上来了呢?我有些不理解,难道这个select模型会出现误通知吗?


终极回答:
您提出了一个很好的问题。

在一般情况下,如果使用 `select` 函数或其他 I/O 多路复用机制,并且它返回了通知有数据可读,那么确实会期望从文件描述符中读取到至少一个字节的数据。这是因为 `select` 函数在通知有数据可读时,文件描述符已经准备好被读取了。

因此,对于 `num_bytes == 0` 的情况,通常不会在正常的 `select` 模型下出现,因为如果 `select` 返回了有数据可读的通知,那么读取操作应该至少读取到一个字节的数据。

然而,这种情况可能会发生在某些特殊情况下,比如:

1. 硬件故障:例如,串口接收缓冲区可能已满,导致无法将数据写入应用程序的缓冲区,从而导致读取操作返回 0 字节。
2. 并发操作:例如,在多线程或多进程环境中,可能会发生竞争条件,导致文件描述符被多个线程或进程同时操作,从而导致某些读取操作返回 0 字节。

虽然这种情况很少发生,并且在大多数情况下,`select` 返回了有数据可读的通知,确实会从文件描述符中读取到至少一个字节的数据。但在编写健壮的程序时,应该考虑到所有可能的情况,并且要有适当的错误处理机制来应对这些情况的发生。

因此,对于 `num_bytes == 0` 的情况,除了串口关闭外,还可能存在其他特殊情况,需要根据实际情况进行适当的处理。

$date = microtime(true);// 返回浮点数,小数点前面是当前时间的时间戳,小数点后为当前时间的微秒
var_dump($date);
// 输出:float(1566897763.0927)



PHP的round函数用于四舍五入浮点数。它的作用是返回最接近一个数字的整数,也可以指定小数点后的位数。例如:

$float = 3.14159;
$rounded = round($float, 2); // 返回 3.14
$rounded = round($float); // 返回 3


要求:timestamp 时间戳 :"timestamp": "1709986011923"        #13位的毫秒数,时间戳(精确到毫秒),当前时间5分钟内请求有效
实现:
cat sendmsg_2.php

php sendmsg_2.php
1709986816.8926         #获取当前Unix时间戳,包括微秒  
1709986816893            #转换为毫秒

Mac下面压缩是zip的,放FreeBSD下面怎么解压呢?
FreeBSD下面安装unzip的方法是:
pkg install  -y unzip #注意:-y是安装在unzip的前面才行

二是:Port方式安装:
-->whereis unzip  查找port源
一般是/usr/ports/archivers/unzip
cd /usr/ports/archivers/unzip
make install clean
rehash    ---在不重启服务器的条件使安装了的命令生效
就可以用unzip命令了 。。
然后通过ftp上传PHPWind_GBK_5[1].3.zip
用unzip PHPWind_GBK_5[1].3.zip
在服务器上解压。。

===> Options unchanged
/!\ WARNING /!\

You have security/openssl installed but do not have
DEFAULT_VERSIONS+=ssl=openssl set in your make.conf

===>  License Info-ZIP accepted by the user
===>   unzip-6.0_8 depends on file: /usr/local/sbin/pkg - found
=> unzip60.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch https://downloads.sourceforge.net/project/infozip/UnZip%206.x%20%28latest%29/UnZip%206.0/unzip60.tar.gz
===>   Generating temporary packing list
install  -s -m 555 /usr/ports/archivers/unzip/work/unzip60/unzip  /usr/ports/archivers/unzip/work/stage/usr/local/bin
cd /usr/ports/archivers/unzip/work/unzip60 &&  install  -s -m 555 funzip unzipsfx /usr/ports/archivers/unzip/work/stage/usr/local/bin
/bin/ln -sf unzip /usr/ports/archivers/unzip/work/stage/usr/local/bin/zipinfo
install  -m 555 /usr/ports/archivers/unzip/work/unzip60/unix/zipgrep /usr/ports/archivers/unzip/work/stage/usr/local/bin
install  -m 444 /usr/ports/archivers/unzip/work/unzip60/man/unzip.1  /usr/ports/archivers/unzip/work/stage/usr/local/share/man/man1
cd /usr/ports/archivers/unzip/work/unzip60/man && install  -m 444 funzip.1 unzipsfx.1 zipgrep.1 zipinfo.1  /usr/ports/archivers/unzip/work/stage/usr/local/share/man/man1
cd /usr/ports/archivers/unzip/work/unzip60 && install  -m 0644 README WHERE /usr/ports/archivers/unzip/work/stage/usr/local/share/doc/unzip
====> Compressing man pages (compress-man)
===>  Installing for unzip-6.0_8
===>  Checking if unzip is already installed
===>   Registering installation for unzip-6.0_8
Installing unzip-6.0_8...
===>  Cleaning for unzip-6.0_8

来自:https://dude6.com/article/182115.html
问题:
php的这段代码,不支持访问http时redirect到https,如:
访问:http://jtgl.beijing.gov.cn/jgj/lszt/659722/660341/index.html
307 Temporary Redirect导到:https://jtgl.beijing.gov.cn/jgj/lszt/659722/660341/index.html

请将该函数修改成能自动导到https并获取到相应body内容:
//发起https的get请求
function https_get($url,$timeout=120){
   $curl = curl_init();
   curl_setopt($curl, CURLOPT_URL, $url);
   curl_setopt($curl, CURLOPT_HEADER, 0);
   curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
   curl_setopt($curl, CURLOPT_TIMEOUT,$timeout);
   curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);  // 跳过检查                                                                                                                  
   curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);  // 跳过检查                                                                                                                  
   $res = curl_exec($curl);                                                                                                                                                          
   curl_close($curl);                                                                                                                                                                
   return $res;   //返回json对象                                                                                                                                                    
}  

回答:
要在PHP中自动将HTTP请求重定向到HTTPS并获取响应内容,您可以使用curl来检测HTTP响应头中的重定向,然后执行相应的HTTPS请求。以下是修改后的函数示例:

function https_get($url, $timeout = 120) {
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_HEADER, true);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); // 启用重定向跟随

    $response = curl_exec($curl);

    $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    if ($httpCode == 301 || $httpCode == 302) {
        $matches = array();
        preg_match('/Location:(.*?)\n/', $response, $matches);
        $newUrl = trim(array_pop($matches));

        if (!empty($newUrl)) {
            curl_setopt($curl, CURLOPT_URL, $newUrl);
            $response = curl_exec($curl);
        }
    }

    curl_close($curl);
    return $response;
}

$url = "http://jtgl.beijing.gov.cn/jgj/lszt/659722/660341/index.html";
$response = https_get($url);
echo $response;


php -a 测试是OK的。




问题二:那直接在shell下用curl命令实现上面307的Location转向获取到转向后的内容,用什么参数实现呢?我记得好像是有相应参数的。
是的,您可以使用`curl`命令行工具来获取重定向后的内容。要实现HTTP 307重定向的自动跟随,您可以使用`-L`或`--location`参数,这会让`curl`自动跟随重定向并获取最终的内容。下面是示例:


使用`-L`参数,`curl`将自动处理HTTP 307 Temporary Redirect,并获取最终的内容。

3XX response code


       -L, --location
              (HTTP) If the server reports that the requested page has moved to a different location (indicated with a Location: header and a 3XX response code), this option will make
              curl redo the request on the new place. If used together with -i, --include or -I, --head, headers from all requested pages will be shown. When authentication is used, curl
              only sends its credentials to the initial host. If a redirect takes curl to a different host, it will not be able to intercept the user+password. See also --location-
              trusted on how to change this. You can limit the amount of redirects to follow by using the --max-redirs option.
1、命令行直接打开「控制台」应用程序:/System/Applications/Utilities/Console.app
2、手工打开「控制台」应用程序步骤:使用 Spotlight 搜索:点击屏幕右上角的放大镜图标或按下 Command + 空格键,然后在弹出的搜索栏中输入 "控制台"(Console)。

在搜索结果中,你应该会看到 "控制台" 应用程序的图标。点击它以打开应用程序。

一旦打开 "控制台" 应用程序,你将看到左侧的导航栏,其中包含不同类型的日志。你可以选择 "日志报告" 以查看系统日志文件。
==============================================================================================
崩溃报告(Crash Reports):这些报告通常包含有关应用程序或进程崩溃的信息。如果 WindowServer 或其他进程崩溃,相关信息可能会出现在这些报告中。

Spin报告(Spin Reports):Spin 报告包含关于进程的信息,可能会显示进程卡住的情况。这些报告可能提供一些线索,说明哪个进程可能导致了问题。

日志报告(Log Reports):日志报告通常包含系统和应用程序的日志信息。虽然它们不是系统日志,但可能包含有关 WindowServer 或其他进程活动的记录。

诊断报告(Diagnostics Reports):诊断报告通常是系统生成的详细报告,用于识别和解决问题。你可以查看这些报告以获取更多信息。

请打开这些报告,查看是否有与 WindowServer 或其他进程相关的信息,以便更好地了解问题的根本原因。如果你不确定如何解释报告中的信息或需要进一步的帮助,建议联系 Apple 支持或专业人员进行更详细的故障排除。感谢你的耐心和理解。
分页: 1/339 第一页 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 下页 最后页 [ 显示模式: 摘要 | 列表 ]