[实践OK] GO语言中Goroutine 泄露的学习,以及在Go语言中,整个 main 函数中的代码都是在主 goroutine 中执行的。主 goroutine 负责启动程序的执行,并处理后续的逻辑,所以需要用var wg sync.WaitGroup // 创建 WaitGroup,不能提前退出而确保主 goroutine 等待所有子 goroutine 完成。如果不使用这种方式,主 goroutine 可能在子 goroutine 执行之前就结束,导致某些任务未能完成。
Php/Js/Shell/Go jackxiang 2024-10-8 11:50
加密日志
[实践OK]PHP正则实现天气预报UL表格及其里面天气信息内容获取。
Php/Js/Shell/Go jackxiang 2024-6-18 15:58
捕获组与非捕获组概念: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><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><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><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><3级</i>
</p>
```
结果是捕获两个 `span` 标签的 `title` 属性值 `南风` 和 `南风`。如果只有一个 `span` 标签,那么也能成功匹配,只会捕获第一个 `title` 属性值。
文章中的工具用的正则表达式公式: 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><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><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><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><3级</i>
</p>
```
结果是捕获两个 `span` 标签的 `title` 属性值 `南风` 和 `南风`。如果只有一个 `span` 标签,那么也能成功匹配,只会捕获第一个 `title` 属性值。
[实践OK]php的round函数实现将微秒转换为毫秒
Php/Js/Shell/Go jackxiang 2024-3-9 20:20
$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 #转换为毫秒
[实践OK]PHP的CURL支持302/301的跳转的代码写法和Shell下的Curl参数-L实现跳转。
Php/Js/Shell/Go jackxiang 2023-10-29 00:08
问题:
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.
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.
import cycle not allowed
而且如果项目很大的时候,一个包下面有很多 .go 文件,只提示包与包的循环引用(如上图),是很难定位到哪个 .go 文件和哪个 .go 文件直接进行了循环引用,难以排查。
go-cyclic run --dir ~/go_learning/src/pdfwatcher.src.cctv.cn
Failed. 1 circular dependence chains were found.
┌---→ /Users/jackXiang/go_learning/src/pdfwatcher.src.cctv.cn/Requests/Request.go
┆ ↓
└--- /Users/jackXiang/go_learning/src/pdfwatcher.src.cctv.cn/Loger/Loger.go
安装:
go install github.com/elza2/go-cyclic@latest
go: downloading github.com/elza2/go-cyclic v1.1.0
go: downloading github.com/fatih/color v1.15.0
go: downloading golang.org/x/mod v0.8.0
go: downloading github.com/urfave/cli/v2 v2.24.4
go: downloading github.com/mattn/go-isatty v0.0.17
go: downloading github.com/mattn/go-colorable v0.1.13
go: downloading golang.org/x/sys v0.6.0
go: downloading github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673
go: downloading github.com/cpuguy83/go-md2man/v2 v2.0.2
go: downloading github.com/russross/blackfriday/v2 v2.1.0
来自:https://link.zhihu.com/?target=https%3A//github.com/elza2/go-cyclic
而且如果项目很大的时候,一个包下面有很多 .go 文件,只提示包与包的循环引用(如上图),是很难定位到哪个 .go 文件和哪个 .go 文件直接进行了循环引用,难以排查。
go-cyclic run --dir ~/go_learning/src/pdfwatcher.src.cctv.cn
Failed. 1 circular dependence chains were found.
┌---→ /Users/jackXiang/go_learning/src/pdfwatcher.src.cctv.cn/Requests/Request.go
┆ ↓
└--- /Users/jackXiang/go_learning/src/pdfwatcher.src.cctv.cn/Loger/Loger.go
安装:
go install github.com/elza2/go-cyclic@latest
go: downloading github.com/elza2/go-cyclic v1.1.0
go: downloading github.com/fatih/color v1.15.0
go: downloading golang.org/x/mod v0.8.0
go: downloading github.com/urfave/cli/v2 v2.24.4
go: downloading github.com/mattn/go-isatty v0.0.17
go: downloading github.com/mattn/go-colorable v0.1.13
go: downloading golang.org/x/sys v0.6.0
go: downloading github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673
go: downloading github.com/cpuguy83/go-md2man/v2 v2.0.2
go: downloading github.com/russross/blackfriday/v2 v2.1.0
来自:https://link.zhihu.com/?target=https%3A//github.com/elza2/go-cyclic
[实践OK]PHP检测当前字符编码并转码
Php/Js/Shell/Go jackxiang 2023-4-16 11:59
Windows上用curl -d"" 上传的编码是:EUC-CN
curl -d"向东阳 向守仁" XXX.XXXX.com
EUC-CN
来自:https://blog.csdn.net/wuxianbing2012/article/details/79727259
curl -d"向东阳 向守仁" XXX.XXXX.com
EUC-CN
来自:https://blog.csdn.net/wuxianbing2012/article/details/79727259
[解决方案]macbook下面root使用ln:无法创建符号链接"/usr/bin/python":权限不够,MAC /usr/bin/目录下 Operation not permitted的解决。
Php/Js/Shell/Go jackxiang 2022-12-5 01:02
Mac系统 解决 python: No such file or directory
ln -s -f /usr/local/bin/python3.9 /usr/local/bin/python
python #无法解决
zsh: no such file or directory: /usr/local/Cellar/python@3.9/3.9.13_3/bin/python3.9 #在PATH里面有上面的软链接,但还是指向这个最新的py地址
/usr/local/bin/runlike #得把它加到环境变量中去没用,还是指向上面最新的。
which python
python: aliased to /usr/local/Cellar/python@3.9/3.9.13_3/bin/python3.9 #aliased指向了最新的
果然如此,vim ~/.zshrc:
alias python="/usr/local/Cellar/python@3.9/3.9.13_3/bin/python3.9"
alias pip="/usr/local/Cellar/python@3.9/3.9.13_3/bin/pip3.9"
alias pip3="/usr/local/Cellar/python@3.8/3.8.9/bin/pip3.8"
alias pip3.8="/usr/local/Cellar/python@3.8/3.8.9/bin/pip3.8"
alias pip3.9="/usr/local/Cellar/python@3.9/3.9.13_3/bin/pip3.9"
修改为就好了:
alias python="/usr/local/Cellar/python@3.9/3.9.14/bin/python3.9"
alias pip="/usr/local/Cellar/python@3.9/3.9.14/bin/pip3.9"
alias pip3="/usr/local/Cellar/python@3.9/3.9.14/bin/pip3.9"
alias pip3.8="/usr/local/Cellar/python@3.9/3.9.14/bin/pip3.9"
alias pip3.9="/usr/local/Cellar/python@3.9/3.9.14/bin/pip3.9"
ls /usr/local/Cellar/python@3.9/3.9.13_3/bin/python3.9
ls: /usr/local/Cellar/python@3.9/3.9.13_3/bin/python3.9: No such file or directory #因升级更新Mac新版本系统后没有了。
位置:/usr/bin sudo cp -rf python3 python
cp: python: Operation not permitted
ln -s /usr/bin/python3 /usr/bin/python
ln: /usr/bin/python: Operation not permitted
原因:系统保护机制
Disabling SIP
It's also possible to disable System Integrity Protection, but it's generally best to leave it on and do customization in more appropriate locations.
https://stackoverflow.com/questions/36730549/cannot-create-a-symlink-inside-of-usr-bin-even-as-sudo
Restart the system -> long press cmd + R. select a terminal from utilities menu type the following command csrutil disable close terminal and restart system.
来自:https://stackoverflow.com/questions/36730549/cannot-create-a-symlink-inside-of-usr-bin-even-as-sudo
MAC /usr/bin/目录下 Operation not permitted的解决
mac系统下的Rootless机制,让我们在root权限下也不能随心所欲的读写所有路径了,特殊情况下我们需要关闭Rootless时,可尝试如下操作:
1. 重启按住 Command+R,进入恢复模式,打开Terminal。
2. 键入命令 csrutil disable
3. reboot
Rootless机制是对抗恶意程序的最后防线,除非特殊需要时我们才将其关闭,否则保持开启状态
csrutil enable
原文链接:https://blog.csdn.net/king457757706/article/details/70671250
ln -s -f /usr/local/bin/python3.9 /usr/local/bin/python
python #无法解决
zsh: no such file or directory: /usr/local/Cellar/python@3.9/3.9.13_3/bin/python3.9 #在PATH里面有上面的软链接,但还是指向这个最新的py地址
/usr/local/bin/runlike #得把它加到环境变量中去没用,还是指向上面最新的。
which python
python: aliased to /usr/local/Cellar/python@3.9/3.9.13_3/bin/python3.9 #aliased指向了最新的
果然如此,vim ~/.zshrc:
alias python="/usr/local/Cellar/python@3.9/3.9.13_3/bin/python3.9"
alias pip="/usr/local/Cellar/python@3.9/3.9.13_3/bin/pip3.9"
alias pip3="/usr/local/Cellar/python@3.8/3.8.9/bin/pip3.8"
alias pip3.8="/usr/local/Cellar/python@3.8/3.8.9/bin/pip3.8"
alias pip3.9="/usr/local/Cellar/python@3.9/3.9.13_3/bin/pip3.9"
修改为就好了:
alias python="/usr/local/Cellar/python@3.9/3.9.14/bin/python3.9"
alias pip="/usr/local/Cellar/python@3.9/3.9.14/bin/pip3.9"
alias pip3="/usr/local/Cellar/python@3.9/3.9.14/bin/pip3.9"
alias pip3.8="/usr/local/Cellar/python@3.9/3.9.14/bin/pip3.9"
alias pip3.9="/usr/local/Cellar/python@3.9/3.9.14/bin/pip3.9"
ls /usr/local/Cellar/python@3.9/3.9.13_3/bin/python3.9
ls: /usr/local/Cellar/python@3.9/3.9.13_3/bin/python3.9: No such file or directory #因升级更新Mac新版本系统后没有了。
位置:/usr/bin sudo cp -rf python3 python
cp: python: Operation not permitted
ln -s /usr/bin/python3 /usr/bin/python
ln: /usr/bin/python: Operation not permitted
原因:系统保护机制
Disabling SIP
It's also possible to disable System Integrity Protection, but it's generally best to leave it on and do customization in more appropriate locations.
https://stackoverflow.com/questions/36730549/cannot-create-a-symlink-inside-of-usr-bin-even-as-sudo
Restart the system -> long press cmd + R. select a terminal from utilities menu type the following command csrutil disable close terminal and restart system.
来自:https://stackoverflow.com/questions/36730549/cannot-create-a-symlink-inside-of-usr-bin-even-as-sudo
MAC /usr/bin/目录下 Operation not permitted的解决
mac系统下的Rootless机制,让我们在root权限下也不能随心所欲的读写所有路径了,特殊情况下我们需要关闭Rootless时,可尝试如下操作:
1. 重启按住 Command+R,进入恢复模式,打开Terminal。
2. 键入命令 csrutil disable
3. reboot
Rootless机制是对抗恶意程序的最后防线,除非特殊需要时我们才将其关闭,否则保持开启状态
csrutil enable
原文链接:https://blog.csdn.net/king457757706/article/details/70671250
cat short-if.go
go build short-if.go
./short-if
1
SpaceX
./short-if
2
Virgin Galactic
./short-if
0
Space Adventures
如果不加:
rand.Seed(time.Now().Unix())
其值一直是:2
原因是:https://blog.csdn.net/weixin_33816821/article/details/94581126
Go语言的switch语法学习之num的简短声明也可用于switch语句的一部分:
./short-switch
Virgin Galactic
./short-switch
Random spaceline # 4
cat scope-rules.go #几月有多少天的一个判断:
./scope-rules
AD 2018 10 24
default:
day := rand.Intn(31) + 1
fmt.Println(era, year, month, day)
}
fmt.Println(month,day) //作用域不再有了。
go build scope-rules.go
# command-line-arguments
./scope-rules.go:22:14: undefined: month
./scope-rules.go:22:20: undefined: day
包括switch的每个case也是都拥有自己独立的作用域,每个分支里面的day变量在分支结束后,day变量将不再处于作用域之内,switch分支的作用域是唯一一种无需使用大括号标识的作用域。
cat random-date.go
#./random-date
AD 2018 11 30
#./random-date
AD 2018 11 30
研究下闰年:
cat random-date-study.go
./random-date-study
AD 2000 2 18
AD 2000 2 4
AD 2000 2 6
AD 2000 2 8
AD 2000 2 7
AD 2000 2 21
AD 2000 2 7
AD 2000 2 29
AD 2000 2 12
AD 2000 2 12
go build short-if.go
./short-if
1
SpaceX
./short-if
2
Virgin Galactic
./short-if
0
Space Adventures
如果不加:
rand.Seed(time.Now().Unix())
其值一直是:2
原因是:https://blog.csdn.net/weixin_33816821/article/details/94581126
Go语言的switch语法学习之num的简短声明也可用于switch语句的一部分:
./short-switch
Virgin Galactic
./short-switch
Random spaceline # 4
cat scope-rules.go #几月有多少天的一个判断:
./scope-rules
AD 2018 10 24
default:
day := rand.Intn(31) + 1
fmt.Println(era, year, month, day)
}
fmt.Println(month,day) //作用域不再有了。
go build scope-rules.go
# command-line-arguments
./scope-rules.go:22:14: undefined: month
./scope-rules.go:22:20: undefined: day
包括switch的每个case也是都拥有自己独立的作用域,每个分支里面的day变量在分支结束后,day变量将不再处于作用域之内,switch分支的作用域是唯一一种无需使用大括号标识的作用域。
cat random-date.go
#./random-date
AD 2018 11 30
#./random-date
AD 2018 11 30
研究下闰年:
cat random-date-study.go
./random-date-study
AD 2000 2 18
AD 2000 2 4
AD 2000 2 6
AD 2000 2 8
AD 2000 2 7
AD 2000 2 21
AD 2000 2 7
AD 2000 2 29
AD 2000 2 12
AD 2000 2 12
curl -v -d'1)杰克。
2)杰克\r\n3)杰克东
3)你是谁 "a" "b"
[空行的空格全是下划]
4)jack ' x.xxxx.com
来自:https://blog.csdn.net/zhaozhi406/article/details/11131971
https://www.xknote.com/blog/1127037.html
2)杰克\r\n3)杰克东
3)你是谁 "a" "b"
[空行的空格全是下划]
4)jack ' x.xxxx.com
来自:https://blog.csdn.net/zhaozhi406/article/details/11131971
https://www.xknote.com/blog/1127037.html
[实践OK]Centos8环境中配置PHP出现configure: error: Package requirements (oniguruma) were not met
Php/Js/Shell/Go jackxiang 2021-3-3 23:45
在Centos8环境中配置PHP出现如上报错:
原因是没有安装配置oniguruma导致的
解决方法如下:
1、获取源码,2.并解压
wget https://github.com/kkos/oniguruma/archive/v6.9.4.tar.gz -O oniguruma-6.9.4.tar.gz
tar -zxf oniguruma-6.9.4.tar.gz
cd oniguruma-6.9.4
备用下载: http://down.24kplus.com/linux/oniguruma/oniguruma-6.9.4.tar.gz
3、编译安装
./autogen.sh && ./configure --prefix=/usr
make && make install
如果是Centos7环境中的话:
解决方法如下:
yum -y install http://mirror.centos.org/centos-7/7.7.1908/cloud/x86_64/openstack-queens/oniguruma-6.7.0-1.el7.x86_64.rpm
yum -y install http://mirror.centos.org/centos-7/7.7.1908/cloud/x86_64/openstack-queens/oniguruma-devel-6.7.0-1.el7.x86_64.rpm
备用下载:
oniguruma:http://down.24kplus.com/linux/oniguruma/oniguruma-6.7.0-1.el7.x86_64.rpm
oniguruma-devel:http://down.24kplus.com/linux/oniguruma/oniguruma-devel-6.7.0-1.el7.x86_64.rpm
————————————————
版权声明:本文为CSDN博主「薄凉小伙」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Kangshuo2471781030/article/details/107241779
原因是没有安装配置oniguruma导致的
解决方法如下:
1、获取源码,2.并解压
wget https://github.com/kkos/oniguruma/archive/v6.9.4.tar.gz -O oniguruma-6.9.4.tar.gz
tar -zxf oniguruma-6.9.4.tar.gz
cd oniguruma-6.9.4
备用下载: http://down.24kplus.com/linux/oniguruma/oniguruma-6.9.4.tar.gz
3、编译安装
./autogen.sh && ./configure --prefix=/usr
make && make install
如果是Centos7环境中的话:
解决方法如下:
yum -y install http://mirror.centos.org/centos-7/7.7.1908/cloud/x86_64/openstack-queens/oniguruma-6.7.0-1.el7.x86_64.rpm
yum -y install http://mirror.centos.org/centos-7/7.7.1908/cloud/x86_64/openstack-queens/oniguruma-devel-6.7.0-1.el7.x86_64.rpm
备用下载:
oniguruma:http://down.24kplus.com/linux/oniguruma/oniguruma-6.7.0-1.el7.x86_64.rpm
oniguruma-devel:http://down.24kplus.com/linux/oniguruma/oniguruma-devel-6.7.0-1.el7.x86_64.rpm
————————————————
版权声明:本文为CSDN博主「薄凉小伙」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Kangshuo2471781030/article/details/107241779
[实践OK]python获取传入argv参数列表,以及字符为空判断,python退出之退出os._exit(-1)。
Php/Js/Shell/Go jackxiang 2021-2-23 17:43
python excelsearchKeyList.py k.txt
sys.argv[0] = excelsearchKeyList.py
sys.argv[1] = k.txt
二)判断字符为空:
python excelsearchKeyList.py k.txt
原创视频
line is null
line is null
三)判断是否传入新的参数:
来自:https://blog.csdn.net/index20001/article/details/74294945#:~:text=Python%E7%A8%8B%E5%BA%8F%E6%9C%89%E4%B8%A4%E7%A7%8D,%E8%A7%A3%E9%87%8A%E5%99%A8%E5%B0%86%E4%BC%9A%E9%80%80%E5%87%BA%E3%80%82
[实践OK]关于go进行多进程通讯的等待子进程问题学习浅显研究。
Php/Js/Shell/Go jackxiang 2021-1-4 18:53
背景:有一篇朋友圈说是一个k8s里面Server的Pod销毁上报Zookeeper出现IP地址连接还是原来的,用到了zk的watcher,理论上不应该这样,于是查来查去,其大体意思就是说用了Go的多进程,有一个进程去读取配置了,因为配置还是老的,而用到了Go的多进程,于是文末那代码,我看了下,简单,但不明白,于是顺藤摸瓜学习一下这个rsync的原理。
——————————
#tree -L 2 .|grep go
├── loop.go
├── pipe.go
├── waitgrouppointer.go
└── wg.go
#cat loop.go
package main
import (
"fmt"
//"time"
)
func main(){
for i := 0; i < 100 ; i++{
go fmt.Println(i)
}
//time.Sleep(time.Second)
}
这个说是运行太快,子进程没输出主进程就退了,啥也不输出。
#cat pipe.go
package main
import (
"fmt"
//"time"
)
func main() {
c := make(chan bool, 100)
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
c <- true
}(i)
}
for i := 0; i < 100; i++ {
<-c
}
}
这个说是管道要是上万,会耗尽系统管道资源。
#cat waitgroup.go
package main
import (
"fmt"
"sync"
//"time"
)
func main() {
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
wg.Done()
}(i)
}
wg.Wait()
}
这个说是挺好的,因为它用到了原子加减法,这里好像C语言也有类似的函数,
再就是说它是用来阻塞方进程的,WaitGroup 对象内部有一个计数器,最初从0开始,它有三个方法:Add(), Done(), Wait() 用来控制计数器的数量。Add(n) 把计数器设置为n ,Done() 每次把计数器-1 ,wait() 会阻塞代码的运行,直到计数器地值减为0。
这里首先把wg 计数设置为100, 每个for循环运行完毕都把计数器减一,主函数中使用Wait() 一直阻塞,直到wg为零——也就是所有的100个for循环都运行完毕。相对于使用管道来说,WaitGroup 轻巧了许多。
最后,如果要搞裂成函数,得用引用传入,指针变量:
WaitGroup对象不是一个引用类型
WaitGroup对象不是一个引用类型,在通过函数传值的时候需要使用地址:
#cat waitgrouppointer.go
package main
import (
"fmt"
"sync"
//"time"
)
func main() {
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go f(i, &wg)
}
wg.Wait()
}
// 一定要通过指针传值,不然进程会进入死锁状态
func f(i int, wg *sync.WaitGroup) {
fmt.Println(i)
wg.Done()
}
以上来自:https://blog.csdn.net/u013474436/article/details/88749749
溯源来自:https://mp.weixin.qq.com/s/s9G6yDqfeFepbKT6DJASng
#cat wg.go
package main
import (
"fmt"
"sync"
)
func main() {
ok := true
for i := 0; i <1000; i ++ {
var arr []int
wg := sync.WaitGroup{}
for j := 0; j <2; j ++ {
wg.Add(1)
go func() {
defer wg.Done()
arr = append(arr, i)
}()
}
wg.Wait()
if len(arr) < 2 {
fmt.Printf("error:%d \n", i)
ok = false
break
}
}
if ok {
fmt.Println("ok")
}
}
阅读全文
——————————
#tree -L 2 .|grep go
├── loop.go
├── pipe.go
├── waitgrouppointer.go
└── wg.go
#cat loop.go
package main
import (
"fmt"
//"time"
)
func main(){
for i := 0; i < 100 ; i++{
go fmt.Println(i)
}
//time.Sleep(time.Second)
}
这个说是运行太快,子进程没输出主进程就退了,啥也不输出。
#cat pipe.go
package main
import (
"fmt"
//"time"
)
func main() {
c := make(chan bool, 100)
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
c <- true
}(i)
}
for i := 0; i < 100; i++ {
<-c
}
}
这个说是管道要是上万,会耗尽系统管道资源。
#cat waitgroup.go
package main
import (
"fmt"
"sync"
//"time"
)
func main() {
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go func(i int) {
fmt.Println(i)
wg.Done()
}(i)
}
wg.Wait()
}
这个说是挺好的,因为它用到了原子加减法,这里好像C语言也有类似的函数,
再就是说它是用来阻塞方进程的,WaitGroup 对象内部有一个计数器,最初从0开始,它有三个方法:Add(), Done(), Wait() 用来控制计数器的数量。Add(n) 把计数器设置为n ,Done() 每次把计数器-1 ,wait() 会阻塞代码的运行,直到计数器地值减为0。
这里首先把wg 计数设置为100, 每个for循环运行完毕都把计数器减一,主函数中使用Wait() 一直阻塞,直到wg为零——也就是所有的100个for循环都运行完毕。相对于使用管道来说,WaitGroup 轻巧了许多。
最后,如果要搞裂成函数,得用引用传入,指针变量:
WaitGroup对象不是一个引用类型
WaitGroup对象不是一个引用类型,在通过函数传值的时候需要使用地址:
#cat waitgrouppointer.go
package main
import (
"fmt"
"sync"
//"time"
)
func main() {
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++ {
go f(i, &wg)
}
wg.Wait()
}
// 一定要通过指针传值,不然进程会进入死锁状态
func f(i int, wg *sync.WaitGroup) {
fmt.Println(i)
wg.Done()
}
以上来自:https://blog.csdn.net/u013474436/article/details/88749749
溯源来自:https://mp.weixin.qq.com/s/s9G6yDqfeFepbKT6DJASng
#cat wg.go
package main
import (
"fmt"
"sync"
)
func main() {
ok := true
for i := 0; i <1000; i ++ {
var arr []int
wg := sync.WaitGroup{}
for j := 0; j <2; j ++ {
wg.Add(1)
go func() {
defer wg.Done()
arr = append(arr, i)
}()
}
wg.Wait()
if len(arr) < 2 {
fmt.Printf("error:%d \n", i)
ok = false
break
}
}
if ok {
fmt.Println("ok")
}
}
阅读全文
[实践成功]go tcp tcpclient编码
Php/Js/Shell/Go jackxiang 2020-12-30 16:55
Server:echoServer.go
Client:echoClient.go
jackXiang@localhost ~/golearning ./echoClient
jack
read from socket:
jack
xiang
read from socket:
xiang
Q:果然Ok,两个问题探讨下:
1) ip4 := net.ParseIP(ADDR).To4()
sa := &syscall.SockaddrInet4{Port: PORT}
copy(sa.Addr[:], ip4) #这个sa.Addr[:] 冒号啥写法呢?
2)for { 这里面是epoll 吗?}
A:
1.
copy(sa.Addr[:], ip4) #这个sa.Addr[:] 冒号啥写法呢?
sa.Addr 是一个数组,
sa.Addr[:] 将这个数组临时转为切片,底层数组指向sa.Addr数组
方便copy进行切片复制
2. 就是个for{}死循环,防止代码往下执行
来自:
https://mp.weixin.qq.com/s/dRADQ5kUCT80dX7oEAAXyA
https://mp.weixin.qq.com/s/kFHw73w_IIqjKeicesCpZw
Client:echoClient.go
jackXiang@localhost ~/golearning ./echoClient
jack
read from socket:
jack
xiang
read from socket:
xiang
Q:果然Ok,两个问题探讨下:
1) ip4 := net.ParseIP(ADDR).To4()
sa := &syscall.SockaddrInet4{Port: PORT}
copy(sa.Addr[:], ip4) #这个sa.Addr[:] 冒号啥写法呢?
2)for { 这里面是epoll 吗?}
A:
1.
copy(sa.Addr[:], ip4) #这个sa.Addr[:] 冒号啥写法呢?
sa.Addr 是一个数组,
sa.Addr[:] 将这个数组临时转为切片,底层数组指向sa.Addr数组
方便copy进行切片复制
2. 就是个for{}死循环,防止代码往下执行
来自:
https://mp.weixin.qq.com/s/dRADQ5kUCT80dX7oEAAXyA
https://mp.weixin.qq.com/s/kFHw73w_IIqjKeicesCpZw
[实践OK]easyswoole验证器,如何在控制器使用验证例子(demo)
Php/Js/Shell/Go jackxiang 2020-10-8 22:51
验证器:
https://www.bookstack.cn/read/easyswoole-3.x-zh/Components-validate.md
App/HttpController/Index.php
App/HttpController/BaseController.php
统一验证:
class Index extends BaseController
{
function index()
{
$this->response()->write("123");
}
/**
* 验证
*
* {@inheritdoc}
* @see \App\HttpController\Index\Index::validateRule()
*/
protected function validateRule(?string $action): ?Validate
{
$v = new Validate();
$params = $this->request()->getRequestParam();
echo "Here:\n";
var_dump($action);
switch ($action) {
case 'index':
{
$v->addColumn('title', '竞赛标题')
->required('不能为空')
->notEmpty();
$v->addColumn('limit', '每页条数')
->integer();
$v->addColumn('page', '当前页码')
->integer();
if (isset($params['recommend_status'])) {
$v->addColumn('recommend_status', '推荐状态')->integer();
}
if (isset($params['act_status'])) {
$v->addColumn('act_status', '活动状态')->integer();
}
break;
}
case 'searchActivity':
{
$v->addColumn('title', '竞赛标题')
->required('不能为空')
->notEmpty();
$v->addColumn('limit', '每页条数')
->integer();
$v->addColumn('page', '当前页码')
->integer();
if (isset($params['recommend_status'])) {
$v->addColumn('recommend_status', '推荐状态')->integer();
}
if (isset($params['act_status'])) {
$v->addColumn('act_status', '活动状态')->integer();
}
break;
}
case 'getRobotAnswer':
{
$v->addColumn('topic_id', '题目id')
->required('不能为空')
->integer();
$v->addColumn('score', '积分')
->integer();
break;
}
case 'saveActivity':
{
$v->addColumn('title', '竞赛标题')
->required('不能为空')
->notEmpty();
$v->addColumn('type', '展示模式')
->required('不能为空')
->integer();
$v->addColumn('description', '竞赛描述')
->required('不能为空')
->notEmpty();
$v->addColumn('start_time', '开始时间')
->required('不能为空')
->integer();
$v->addColumn('end_time', '结束时间')
->required('不能为空')
->integer();
$v->addColumn('paper_status', '试卷状态')
->required('不能为空')
->integer();
$v->addColumn('act_status', '活动状态')
->required('不能为空')
->integer();
if (isset($params['act_id'])) {
$v->addColumn('act_id', '竞赛id')->integer();
}
if (isset($params['recommend_status'])) {
$v->addColumn('recommend_status', '推荐状态')->integer();
}
if (isset($params['recommend_index'])) {
$v->addColumn('recommend_index', '推荐序号')->integer();
}
break;
}
case 'delActivity':
{
$v->addColumn('act_id', '竞赛id')
->required('不能为空')
->integer()
->min(0);
break;
}
case 'getActivity':
{
$v->addColumn('act_id', '竞赛id')
->required('不能为空')
->integer();
break;
}
case 'getActivityList':
{
$v->addColumn('recommend_status', '推荐状态')
->required('不能为空')
->integer();
$v->addColumn('limit', '列表数')
->required('不能为空')
->integer();
break;
}
case 'getPaper':
{
$v->addColumn('act_id', '竞赛id')
->required('不能为空')
->integer();
$v->addColumn('paper_nums', '试卷题量')
->required('不能为空')
->integer();
break;
}
case 'addPaperTopic':
{
$v->addColumn('act_id', '竞赛id')
->required('不能为空')
->integer();
$v->addColumn('topic_id', '题目id')
->required('不能为空')
->notEmpty();
$v->addColumn('topic_title', '题目标题')
->required('不能为空')
->notEmpty();
$v->addColumn('topic_label', '题目标签')
->required('不能为空')
->notEmpty();
break;
}
case 'delPaperTopic':
{
$v->addColumn('act_id', '竞赛id')
->required('不能为空')
->integer();
$v->addColumn('topic_id', '题目id')
->required('不能为空')
->notEmpty();
break;
}
case 'updatePaper':
{
$v->addColumn('act_id', '竞赛id')
->required('不能为空')
->integer();
$v->addColumn('type', '答题类型')
->required('不能为空')
->integer();
$v->addColumn('nums', '题量')
->required('不能为空')
->integer();
break;
}
case 'updateScoreSet':
{
$v->addColumn('per_score', '答对得分')
->required('不能为空')
->integer();
$v->addColumn('win_score', '获胜得分')
->required('不能为空')
->integer();
$v->addColumn('fail_score', '失败得分')
->required('不能为空')
->integer();
break;
}
}
return $v;
}
App/HttpController/BaseController.php
https://www.bookstack.cn/read/easyswoole-3.x-zh/Components-validate.md
App/HttpController/Index.php
App/HttpController/BaseController.php
统一验证:
class Index extends BaseController
{
function index()
{
$this->response()->write("123");
}
/**
* 验证
*
* {@inheritdoc}
* @see \App\HttpController\Index\Index::validateRule()
*/
protected function validateRule(?string $action): ?Validate
{
$v = new Validate();
$params = $this->request()->getRequestParam();
echo "Here:\n";
var_dump($action);
switch ($action) {
case 'index':
{
$v->addColumn('title', '竞赛标题')
->required('不能为空')
->notEmpty();
$v->addColumn('limit', '每页条数')
->integer();
$v->addColumn('page', '当前页码')
->integer();
if (isset($params['recommend_status'])) {
$v->addColumn('recommend_status', '推荐状态')->integer();
}
if (isset($params['act_status'])) {
$v->addColumn('act_status', '活动状态')->integer();
}
break;
}
case 'searchActivity':
{
$v->addColumn('title', '竞赛标题')
->required('不能为空')
->notEmpty();
$v->addColumn('limit', '每页条数')
->integer();
$v->addColumn('page', '当前页码')
->integer();
if (isset($params['recommend_status'])) {
$v->addColumn('recommend_status', '推荐状态')->integer();
}
if (isset($params['act_status'])) {
$v->addColumn('act_status', '活动状态')->integer();
}
break;
}
case 'getRobotAnswer':
{
$v->addColumn('topic_id', '题目id')
->required('不能为空')
->integer();
$v->addColumn('score', '积分')
->integer();
break;
}
case 'saveActivity':
{
$v->addColumn('title', '竞赛标题')
->required('不能为空')
->notEmpty();
$v->addColumn('type', '展示模式')
->required('不能为空')
->integer();
$v->addColumn('description', '竞赛描述')
->required('不能为空')
->notEmpty();
$v->addColumn('start_time', '开始时间')
->required('不能为空')
->integer();
$v->addColumn('end_time', '结束时间')
->required('不能为空')
->integer();
$v->addColumn('paper_status', '试卷状态')
->required('不能为空')
->integer();
$v->addColumn('act_status', '活动状态')
->required('不能为空')
->integer();
if (isset($params['act_id'])) {
$v->addColumn('act_id', '竞赛id')->integer();
}
if (isset($params['recommend_status'])) {
$v->addColumn('recommend_status', '推荐状态')->integer();
}
if (isset($params['recommend_index'])) {
$v->addColumn('recommend_index', '推荐序号')->integer();
}
break;
}
case 'delActivity':
{
$v->addColumn('act_id', '竞赛id')
->required('不能为空')
->integer()
->min(0);
break;
}
case 'getActivity':
{
$v->addColumn('act_id', '竞赛id')
->required('不能为空')
->integer();
break;
}
case 'getActivityList':
{
$v->addColumn('recommend_status', '推荐状态')
->required('不能为空')
->integer();
$v->addColumn('limit', '列表数')
->required('不能为空')
->integer();
break;
}
case 'getPaper':
{
$v->addColumn('act_id', '竞赛id')
->required('不能为空')
->integer();
$v->addColumn('paper_nums', '试卷题量')
->required('不能为空')
->integer();
break;
}
case 'addPaperTopic':
{
$v->addColumn('act_id', '竞赛id')
->required('不能为空')
->integer();
$v->addColumn('topic_id', '题目id')
->required('不能为空')
->notEmpty();
$v->addColumn('topic_title', '题目标题')
->required('不能为空')
->notEmpty();
$v->addColumn('topic_label', '题目标签')
->required('不能为空')
->notEmpty();
break;
}
case 'delPaperTopic':
{
$v->addColumn('act_id', '竞赛id')
->required('不能为空')
->integer();
$v->addColumn('topic_id', '题目id')
->required('不能为空')
->notEmpty();
break;
}
case 'updatePaper':
{
$v->addColumn('act_id', '竞赛id')
->required('不能为空')
->integer();
$v->addColumn('type', '答题类型')
->required('不能为空')
->integer();
$v->addColumn('nums', '题量')
->required('不能为空')
->integer();
break;
}
case 'updateScoreSet':
{
$v->addColumn('per_score', '答对得分')
->required('不能为空')
->integer();
$v->addColumn('win_score', '获胜得分')
->required('不能为空')
->integer();
$v->addColumn('fail_score', '失败得分')
->required('不能为空')
->integer();
break;
}
}
return $v;
}
App/HttpController/BaseController.php
sed之h;H和:a;N;ba使用精解(对段落进行操作)
Php/Js/Shell/Go jackxiang 2020-9-18 16:03
这是老式编程语bai言里的标签跳转, 相当于C语言du里面的goto语句
可以实现 分支选择zhi, 循环等功能
sed '/^AA/ba;s/$/ NO/;b;:a;s/$/ YES/' 解读如下dao
sed是逐行扫描的
/^AA/ba;s/$/ NO/ 意思是如果当前行句首是AA
则跳转到标签a,执行s/$/ YES/ 即在行末插入YES (这里使用替换s命令实现插入)
否则执行s/$/ NO/, 在行末插入NO
对所有行都执行这种操作, 大功告成
echo 1 2 3 4 5 6 7 8 9 10 | perl -p -e 's#(\d+) #\1\n#g' | sort -n -k 1 | sed -e :a -e '$d;N;2,3ba' -e 'P;D'
3ba表示去掉最后3行,你要保留最新的5个,那就是5ba好了
sed -n '/^Handle/{:a;N;/\n$/!{$!ba};s/.*Range Size: \([^\n]*\).*/\1/p}' file
[解析]
文本就3个段落,2个空行为分割,用sed首先想到肯定是以空行为分割,把一整段文本读取在一起,然后统一进行匹配和替换,特别注意N读取内容匹配空行是 /\n$/ ,而不是一般的 /^$/ ,另一个问题是到了尾行因为没有下面的空行来激活,所以我们要在前面加个尾行的匹配跳转。这样就可以成功替换以Handle开头的段落内容,如果没匹配到也当然不会打印。
sed -n 'H;/^$/!{$!b};x;s/\nHandle.*Range Size: \([^\n]*\).*/\1/p' file
[解析]
因为是以空行为分割,H 追加到 hold space ,后面的替换只对空行或者最后一行才执行,否则都会跳过,也只有符合关键字的才会被替换打印。其他的行则因为 -n 的原因不会被输出。
From:https://blog.csdn.net/woshizhangliang999/article/details/53379158
可以实现 分支选择zhi, 循环等功能
sed '/^AA/ba;s/$/ NO/;b;:a;s/$/ YES/' 解读如下dao
sed是逐行扫描的
/^AA/ba;s/$/ NO/ 意思是如果当前行句首是AA
则跳转到标签a,执行s/$/ YES/ 即在行末插入YES (这里使用替换s命令实现插入)
否则执行s/$/ NO/, 在行末插入NO
对所有行都执行这种操作, 大功告成
echo 1 2 3 4 5 6 7 8 9 10 | perl -p -e 's#(\d+) #\1\n#g' | sort -n -k 1 | sed -e :a -e '$d;N;2,3ba' -e 'P;D'
3ba表示去掉最后3行,你要保留最新的5个,那就是5ba好了
sed -n '/^Handle/{:a;N;/\n$/!{$!ba};s/.*Range Size: \([^\n]*\).*/\1/p}' file
[解析]
文本就3个段落,2个空行为分割,用sed首先想到肯定是以空行为分割,把一整段文本读取在一起,然后统一进行匹配和替换,特别注意N读取内容匹配空行是 /\n$/ ,而不是一般的 /^$/ ,另一个问题是到了尾行因为没有下面的空行来激活,所以我们要在前面加个尾行的匹配跳转。这样就可以成功替换以Handle开头的段落内容,如果没匹配到也当然不会打印。
sed -n 'H;/^$/!{$!b};x;s/\nHandle.*Range Size: \([^\n]*\).*/\1/p' file
[解析]
因为是以空行为分割,H 追加到 hold space ,后面的替换只对空行或者最后一行才执行,否则都会跳过,也只有符合关键字的才会被替换打印。其他的行则因为 -n 的原因不会被输出。
From:https://blog.csdn.net/woshizhangliang999/article/details/53379158
[实践OK]使用OSC52实现iTerm2远程pbcopy。
Php/Js/Shell/Go jackxiang 2020-5-25 10:26
从Macbook通过iTerm2的SSH连接到其它linux实现iTerm2远程pbcopy,前几周我也想过,但是不知怎么实现,
前两天鸟哥在其微信朋友圈里贴了一个PHP版本的实现思路,我这实践了一下,用Go语言实现了使用起来顺手,
于是在想,可能很多人都有这个需求,于是写下我的实现过程,拿走不谢,PHP是最好的语言没有之一,如下:
使用OSC52实现iTerm2远程pbcopy实现模仿Mac的pbcopy的拷贝最基础原理如下:
关于PHP实现的鸟哥版本pbcopy的详细情况见如下链接:
https://mp.weixin.qq.com/s/-aFTI32LWCJG_7aEuCUBgw
现在,开启swoole顾问的GO实现正文:
上面是摘录来自鸟哥的文章,他是用PHP实现了的,但是PHP不是每台机器都有且没有PHP怎么办呢?
于是用Go歪歪斜斜的写了一个,以力求实现功能就算是很OK了,实践发现果然OK的,有鸟哥加持嘛!
pbcopy.go
在MacBook上面编译成Linux上可运行的pbcopy,如不这样会报-bash: ./pbcopy: 无法执行二进制文件错:
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o pbcopy pbcopy.go
从MAC机上编译成功后把上面的二进制GO文件扔到CentOS的服务器上,修改iTerm2连接远程机器设置,
运行,就成功复制到Mac的剪切板上了,注意一定是用iTerm2软件下ssh连接远程服务器,不是在secureCRT:
echo "osc520 codes" | /home/xiangdong/bin/pbcopy
最后,就是把/home/xiangdong/bin/pbcopy 加到那个Linux 的环境PATH变量里了,如下:
chmod +x ~/bin/pbcopy
vim ~/.bashrc #/home/xiangdong/.bashrc 把这个pbcopy路径加到PATH环境变量里面去,下次不用再输入绝对路径了。
export PATH=/home/xiangdong/bin:$PATH
$tree ~+/bin/
/home/xiangdong/bin/
├── kubeladder
└── pbcopy
就可直接运行pbcopy了,不用加点了:
echo "osc520 codes" |pbcopy
最后,
鸟哥微信朋友圈问了一喙,这个能否在secureCRT里也支持一下呢,可不就可以批量部署到控制机上,拷贝操作更完美了。
目前在secreCRT里运行输出如下:
$echo "osc540 codes" |pbcopy
;;b3NjNTQwIGNvZGVz
乔大妈给了一个纯shell的白膘(月票)版本:
cat ~/.bashrc
alias pbcopy2="(printf '\033]1337;CopyToClipboard=\7'; cat -; printf '\033]1337;EndCopy\7')"
echo "osc520 codes" |pbcopy2
osc520 codes
osc52000 codes
前两天鸟哥在其微信朋友圈里贴了一个PHP版本的实现思路,我这实践了一下,用Go语言实现了使用起来顺手,
于是在想,可能很多人都有这个需求,于是写下我的实现过程,拿走不谢,PHP是最好的语言没有之一,如下:
使用OSC52实现iTerm2远程pbcopy实现模仿Mac的pbcopy的拷贝最基础原理如下:
关于PHP实现的鸟哥版本pbcopy的详细情况见如下链接:
https://mp.weixin.qq.com/s/-aFTI32LWCJG_7aEuCUBgw
现在,开启swoole顾问的GO实现正文:
上面是摘录来自鸟哥的文章,他是用PHP实现了的,但是PHP不是每台机器都有且没有PHP怎么办呢?
于是用Go歪歪斜斜的写了一个,以力求实现功能就算是很OK了,实践发现果然OK的,有鸟哥加持嘛!
pbcopy.go
在MacBook上面编译成Linux上可运行的pbcopy,如不这样会报-bash: ./pbcopy: 无法执行二进制文件错:
CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o pbcopy pbcopy.go
从MAC机上编译成功后把上面的二进制GO文件扔到CentOS的服务器上,修改iTerm2连接远程机器设置,
运行,就成功复制到Mac的剪切板上了,注意一定是用iTerm2软件下ssh连接远程服务器,不是在secureCRT:
echo "osc520 codes" | /home/xiangdong/bin/pbcopy
最后,就是把/home/xiangdong/bin/pbcopy 加到那个Linux 的环境PATH变量里了,如下:
chmod +x ~/bin/pbcopy
vim ~/.bashrc #/home/xiangdong/.bashrc 把这个pbcopy路径加到PATH环境变量里面去,下次不用再输入绝对路径了。
export PATH=/home/xiangdong/bin:$PATH
$tree ~+/bin/
/home/xiangdong/bin/
├── kubeladder
└── pbcopy
就可直接运行pbcopy了,不用加点了:
echo "osc520 codes" |pbcopy
最后,
鸟哥微信朋友圈问了一喙,这个能否在secureCRT里也支持一下呢,可不就可以批量部署到控制机上,拷贝操作更完美了。
目前在secreCRT里运行输出如下:
$echo "osc540 codes" |pbcopy
;;b3NjNTQwIGNvZGVz
乔大妈给了一个纯shell的白膘(月票)版本:
cat ~/.bashrc
alias pbcopy2="(printf '\033]1337;CopyToClipboard=\7'; cat -; printf '\033]1337;EndCopy\7')"
echo "osc520 codes" |pbcopy2
osc520 codes
osc52000 codes