Home PHP Framework Swoole Summary of common problems with PHP Swoole long connections

Summary of common problems with PHP Swoole long connections

Jan 26, 2020 pm 01:48 PM
php swoole

Summary of common problems with PHP Swoole long connections

Connection failure problem

Example

Among them, Redis is common The error report is:

Configuration item: timeout

Error message: Error while reading line from the server

Redis can Configure if the client does not send data to the Redis server after a certain number of seconds, the connection will be closed.

Recommended learning: swoole tutorial

MySQL common errors:

Configuration items: wait_timeout & interactive_timeout

Error message: has gone away

Like the Redis server, MySQL will also clean up useless connections regularly.

How to solve

1. Reconnect when using

2. Send heartbeats regularly to maintain the connection

When using Reconnecting

The advantage is that it is simple, but the disadvantage is that it faces the problem of short connections.

Send heartbeat regularly to maintain connection

Recommended.

How to maintain a long connection

tcp_keepalive implemented in the tcp protocol

The bottom layer of the operating system provides a set of tcpkeepaliveConfiguration:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

tcp_keepalive_time (integer; default: 7200; since Linux 2.2)

The number of seconds a connection needs to be idle before TCP

begins sending out keep-alive probes. Keep-alives are sent only

when the SO_KEEPALIVE socket option is enabled. The default

value is 7200 seconds (2 hours). An idle connection is

terminated after approximately an additional 11 minutes (9

probes an interval of 75 seconds apart) when keep-alive is

enabled.

  

Note that underlying connection tracking mechanisms and

application timeouts may be much shorter.

  

tcp_keepalive_intvl (integer; default: 75; since Linux 2.4)

The number of seconds between TCP keep-alive probes.

  

tcp_keepalive_probes (integer; default: 9; since Linux 2.2)

The maximum number of TCP keep-alive probes to send before

giving up and killing the connection if no response is obtained

from the other end.

8

Copy after login

The bottom layer of Swoole has opened up these configurations, for example:

1

2

3

4

5

6

7

8

9

10

11

?php

  

$server = new \Swoole\Server('127.0.0.1', 6666, SWOOLE_PROCESS);

  

$server->set([

'worker_num' => 1,

'open_tcp_keepalive' => 1,

'tcp_keepidle' => 4, // 对应tcp_keepalive_time

'tcp_keepinterval' => 1, // 对应tcp_keepalive_intvl

'tcp_keepcount' => 5, // 对应tcp_keepalive_probes

]);

Copy after login

Among them:

1

2

3

4

5

'open_tcp_keepalive' => 1, // 总开关,用来开启tcp_keepalive

'tcp_keepidle' => 4, // 4s没有数据传输就进行检测

// 检测的策略如下:

'tcp_keepinterval' => 1, // 1s探测一次,即每隔1s给客户端发一个包(然后客户端可能会回一个ack的包,如果服务端收到了这个ack包,那么说明这个连接是活着的)

'tcp_keepcount' => 5, // 探测的次数,超过5次后客户端还没有回ack包,那么close此连接

Copy after login

Let’s Let’s experience the actual test. The server script is as follows:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

<?php

  

$server = new \Swoole\Server(&#39;127.0.0.1&#39;, 6666, SWOOLE_PROCESS);

  

$server->set([

&#39;worker_num&#39; => 1,

&#39;open_tcp_keepalive&#39; => 1, // 开启tcp_keepalive

&#39;tcp_keepidle&#39; => 4, // 4s没有数据传输就进行检测

&#39;tcp_keepinterval&#39; => 1, // 1s探测一次

&#39;tcp_keepcount&#39; => 5, // 探测的次数,超过5次后还没有回包close此连接

]);

  

$server->on(&#39;connect&#39;, function ($server, $fd) {

var_dump("Client: Connect $fd");

});

  

$server->on(&#39;receive&#39;, function ($server, $fd, $reactor_id, $data) {

var_dump($data);

});

  

$server->on(&#39;close&#39;, function ($server, $fd) {

var_dump("close fd $fd");

});

  

$server->start();

Copy after login

Let’s start this server:

1

~/codeDir/phpCode/hyperf-skeleton # php server.php

Copy after login

Then capture the packet through tcpdump:

~/codeDir/phpCode /hyperf-skeleton # tcpdump -i lo port 6666

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on lo, link-type EN10MB (Ethernet) , capture size 262144 bytes

We are listening for data packets on port 6666 on lo at this time.

Then we use the client to connect to it:

1

~/codeDir/phpCode/hyperf-skeleton # nc 127.0.0.1 6666

Copy after login

At this time, the server will print out the message:

1

2

~/codeDir/phpCode/hyperf-skeleton # php server.php

string(17) "Client: Connect 1"

Copy after login

The output information of tcpdump is as follows:

1

2

3

4

5

6

7

8

9

01:48:40.178439 IP localhost.33933 > localhost.6666: Flags [S], seq 43162537, win 43690, options [mss 65495,sackOK,TS val 9833698 ecr 0,nop,wscale 7], length 0

01:48:40.178484 IP localhost.6666 > localhost.33933: Flags [S.], seq 1327460565, ack 43162538, win 43690, options [mss 65495,sackOK,TS val 9833698 ecr 9833698,nop,wscale 7], length 0

01:48:40.178519 IP localhost.33933 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 9833698 ecr 9833698], length 0

01:48:44.229926 IP localhost.6666 > localhost.33933: Flags [.], ack 1, win 342, options [nop,nop,TS val 9834104 ecr 9833698], length 0

01:48:44.229951 IP localhost.33933 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 9834104 ecr 9833698], length 0

01:48:44.229926 IP localhost.6666 > localhost.33933: Flags [.], ack 1, win 342, options [nop,nop,TS val 9834104 ecr 9833698], length 0

01:48:44.229951 IP localhost.33933 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 9834104 ecr 9833698], length 0

01:48:44.229926 IP localhost.6666 > localhost.33933: Flags [.], ack 1, win 342, options [nop,nop,TS val 9834104 ecr 9833698], length 0

// 省略了其他的输出

Copy after login

We will find that at the beginning, the three-way handshake packet will be printed:

1

2

3

01:48:40.178439 IP localhost.33933 > localhost.6666: Flags [S], seq 43162537, win 43690, options [mss 65495,sackOK,TS val 9833698 ecr 0,nop,wscale 7], length 0

01:48:40.178484 IP localhost.6666 > localhost.33933: Flags [S.], seq 1327460565, ack 43162538, win 43690, options [mss 65495,sackOK,TS val 9833698 ecr 9833698,nop,wscale 7], length 0

01:48:40.178519 IP localhost.33933 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 9833698 ecr 9833698], length 0

Copy after login

Then, it will stay for 4s without any packet output.

After that, a group will be printed out every 1 second or so:

1

2

01:52:54.359341 IP localhost.6666 > localhost.43101: Flags [.], ack 1, win 342, options [nop,nop,TS val 9859144 ecr 9858736], length 0

 01:52:54.359377 IP localhost.43101 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 9859144 ecr 9855887], length 0

Copy after login
Copy after login

In fact, this is the strategy we configured:

1

2

&#39;tcp_keepinterval&#39; => 1, // 1s探测一次

&#39;tcp_keepcount&#39; => 5, // 探测的次数,超过5次后还没有回包close此连接

Copy after login

Because the bottom layer of our operating system will automatically The client responds with ack, so the connection will not be closed after 5 probes. The bottom layer of the operating system will continuously send a group of packets like this:

1

2

01:52:54.359341 IP localhost.6666 > localhost.43101: Flags [.], ack 1, win 342, options [nop,nop,TS val 9859144 ecr 9858736], length 0

 01:52:54.359377 IP localhost.43101 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 9859144 ecr 9855887], length 0

Copy after login
Copy after login

If we want to close the connection after testing 5 times, we can disable the packets on port 6666:

1

~/codeDir/phpCode/hyperf-skeleton # iptables -A INPUT -p tcp --dport 6666 -j DROP

Copy after login

This will Disable all packets coming from port 6666. Naturally, the server will not be able to receive ack packets sent from the client.

Then the server will print out close after 5 seconds (the server actively calls the close method and sends a FIN packet to the client):

1

2

3

~/codeDir/phpCode/hyperf-skeleton # php server.php

string(17) "Client: Connect 1"

string(10) "close fd 1"

Copy after login
Copy after login

Let’s restore the iptables rules:

1

~/codeDir/phpCode # iptables -D INPUT -p tcp -m tcp --dport 6666 -j DROP

Copy after login

That is, the rules we set are deleted.

The heartbeat function is implemented through tcp_keepalive. The advantage is that it is simple. You can complete this function without writing code, and the heartbeat packet sent is small. The disadvantage is that it depends on the network environment of the system. It must be ensured that both the server and the client implement such functions, and the client needs to cooperate in sending heartbeat packets.

Another more serious shortcoming is that if the client and the server are not directly connected, but are connected through a proxy, such as the socks5 proxy, it will only forward application layer packets and not forward them. For lower-level TCP detection packets, the heartbeat function will be invalid.

So, Swoole provides other solutions, a set of configurations for detecting dead connections.

1

2

&#39;heartbeat_check_interval&#39; => 1, // 1s探测一次

&#39;heartbeat_idle_time&#39; => 5, // 5s未发送数据包就close此连接

Copy after login

heartbeat implemented by swoole

Let’s test it:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

<?php

  

$server = new \Swoole\Server(&#39;127.0.0.1&#39;, 6666, SWOOLE_PROCESS);

  

$server->set([

&#39;worker_num&#39; => 1,

&#39;heartbeat_check_interval&#39; => 1, // 1s探测一次

&#39;heartbeat_idle_time&#39; => 5, // 5s未发送数据包就close此连接

]);

  

$server->on(&#39;connect&#39;, function ($server, $fd) {

var_dump("Client: Connect $fd");

});

  

$server->on(&#39;receive&#39;, function ($server, $fd, $reactor_id, $data) {

var_dump($data);

});

  

$server->on(&#39;close&#39;, function ($server, $fd) {

var_dump("close fd $fd");

});

  

$server->start();

Copy after login

Then start the server:

~/codeDir/phpCode/hyperf- skeleton # php server.php

Then start tcpdump:

1

2

3

~/codeDir/phpCode # tcpdump -i lo port 6666

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes

Copy after login

Then start the client:

~/codeDir/phpCode/hyperf-skeleton # nc 127.0.0.1 6666

At this time, the server prints:

1

2

~/codeDir/phpCode/hyperf-skeleton # php server.php

 string(17) "Client: Connect 1"

Copy after login

Then tcpdump prints:

1

2

3

02:48:32.516093 IP localhost.42123 > localhost.6666: Flags [S], seq 1088388248, win 43690, options [mss 65495,sackOK,TS val 10193342 ecr 0,nop,wscale 7], length 0

02:48:32.516133 IP localhost.6666 > localhost.42123: Flags [S.], seq 80508236, ack 1088388249, win 43690, options [mss 65495,sackOK,TS val 10193342 ecr 10193342,nop,wscale 7], length 0

02:48:32.516156 IP localhost.42123 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 10193342 ecr 10193342], length 0

Copy after login

This is the three-way handshake information.

Then after 5 seconds, tcpdump will print out:

02:48:36.985027 IP localhost.6666 > localhost.42123: Flags [F.], seq 1, ack 1, win 342, options [nop,nop,TS val 10193789 ecr 10193342], length 0

02:48:36.992172 IP localhost.42123 > localhost.6666: Flags [.], ack 2, win 342, options [nop,nop,TS val 10193790 ecr 10193789], length 0

That is, the server sent a FIN packet. Because the client sent no data, Swoole closed the connection.

Then the server will print:

1

2

3

~/codeDir/phpCode/hyperf-skeleton # php server.php

string(17) "Client: Connect 1"

string(10) "close fd 1"

Copy after login
Copy after login

So, there are certain differences between heartbeat and tcp keepalive. Tcp keepalive has the function of keeping the connection alive, but heartbeat saves It simply detects a connection without data and then closes it. It can only be configured on the server side. If it needs to be kept alive, the client can also cooperate to send heartbeats.

如果我们不想让服务端close掉连接,那么就得在应用层里面不断的发送数据包来进行保活,例如我在nc客户端里面不断的发送包:

1

2

3

4

5

6

7

8

9

10

~/codeDir/phpCode/hyperf-skeleton # nc 127.0.0.1 6666

ping

ping

ping

ping

ping

ping

ping

ping

ping

Copy after login

我发送了9个ping包给服务器,tcpdump的输出如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

// 省略了三次握手的包

02:57:53.697363 IP localhost.44195 > localhost.6666: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 10249525 ecr 10249307], length 5

02:57:53.697390 IP localhost.6666 > localhost.44195: Flags [.], ack 6, win 342, options [nop,nop,TS val 10249525 ecr 10249525], length 0

02:57:55.309532 IP localhost.44195 > localhost.6666: Flags [P.], seq 6:11, ack 1, win 342, options [nop,nop,TS val 10249686 ecr 10249525], length 5

02:57:55.309576 IP localhost.6666 > localhost.44195: Flags [.], ack 11, win 342, options [nop,nop,TS val 10249686 ecr 10249686], length 0

02:57:58.395206 IP localhost.44195 > localhost.6666: Flags [P.], seq 11:16, ack 1, win 342, options [nop,nop,TS val 10249994 ecr 10249686], length 5

02:57:58.395239 IP localhost.6666 > localhost.44195: Flags [.], ack 16, win 342, options [nop,nop,TS val 10249994 ecr 10249994], length 0

02:58:01.858094 IP localhost.44195 > localhost.6666: Flags [P.], seq 16:21, ack 1, win 342, options [nop,nop,TS val 10250341 ecr 10249994], length 5

02:58:01.858126 IP localhost.6666 > localhost.44195: Flags [.], ack 21, win 342, options [nop,nop,TS val 10250341 ecr 10250341], length 0

02:58:04.132584 IP localhost.44195 > localhost.6666: Flags [P.], seq 21:26, ack 1, win 342, options [nop,nop,TS val 10250568 ecr 10250341], length 5

02:58:04.132609 IP localhost.6666 > localhost.44195: Flags [.], ack 26, win 342, options [nop,nop,TS val 10250568 ecr 10250568], length 0

02:58:05.895704 IP localhost.44195 > localhost.6666: Flags [P.], seq 26:31, ack 1, win 342, options [nop,nop,TS val 10250744 ecr 10250568], length 5

02:58:05.895728 IP localhost.6666 > localhost.44195: Flags [.], ack 31, win 342, options [nop,nop,TS val 10250744 ecr 10250744], length 0

02:58:07.150265 IP localhost.44195 > localhost.6666: Flags [P.], seq 31:36, ack 1, win 342, options [nop,nop,TS val 10250870 ecr 10250744], length 5

02:58:07.150288 IP localhost.6666 > localhost.44195: Flags [.], ack 36, win 342, options [nop,nop,TS val 10250870 ecr 10250870], length 0

02:58:08.349124 IP localhost.44195 > localhost.6666: Flags [P.], seq 36:41, ack 1, win 342, options [nop,nop,TS val 10250990 ecr 10250870], length 5

02:58:08.349156 IP localhost.6666 > localhost.44195: Flags [.], ack 41, win 342, options [nop,nop,TS val 10250990 ecr 10250990], length 0

02:58:09.906223 IP localhost.44195 > localhost.6666: Flags [P.], seq 41:46, ack 1, win 342, options [nop,nop,TS val 10251145 ecr 10250990], length 5

02:58:09.906247 IP localhost.6666 > localhost.44195: Flags [.], ack 46, win 342, options [nop,nop,TS val 10251145 ecr 10251145], length 0

Copy after login

有9组数据包的发送。(这里的Flags [P.]代表Push的含义)

此时服务器还没有close掉连接,实现了客户端保活连接的功能。然后我们停止发送ping,过了5秒后tcpdump就会输出一组:

02:58:14.811761 IP localhost.6666 > localhost.44195: Flags [F.], seq 1, ack 46, win 342, options [nop,nop,TS val 10251636 ecr 10251145], length 0

02:58:14.816420 IP localhost.44195 > localhost.6666: Flags [.], ack 2, win 342, options [nop,nop,TS val 10251637 ecr 10251636], length 0

服务端那边发送了FIN包,说明服务端close掉了连接。服务端的输出如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

~/codeDir/phpCode/hyperf-skeleton # php server.php

string(17) "Client: Connect 1"

string(5) "ping

"

string(5) "ping

"

string(5) "ping

"

string(5) "ping

"

string(5) "ping

"

string(5) "ping

"

string(5) "ping

"

string(5) "ping

"

string(5) "ping

"

string(10) "close fd 1"

Copy after login

然后我们在客户端那边ctrl + c来关闭连接:

1

2

3

4

5

6

7

8

9

10

11

12

13

~/codeDir/phpCode/hyperf-skeleton # nc 127.0.0.1 6666

ping

ping

ping

ping

ping

ping

ping

ping

ping

^Cpunt!

 

~/codeDir/phpCode/hyperf-skeleton #

Copy after login

此时,tcpdump的输出如下:

1

2

03:03:02.257667 IP localhost.44195 > localhost.6666: Flags [F.], seq 46, ack 2, win 342, options [nop,nop,TS val 10280414 ecr 10251636], length 0

03:03:02.257734 IP localhost.6666 > localhost.44195: Flags [R], seq 2678621620, win 0, length 0

Copy after login

应用层心跳

1、制定ping/pong协议(mysql等自带ping协议)

2、客户端灵活的发送ping心跳包

3、服务端OnRecive检查可用性回复pong

例如:

1

2

3

4

5

6

7

8

9

10

$server->on(&#39;receive&#39;, function (\Swoole\Server $server, $fd, $reactor_id, $data)

{

if ($data == &#39;ping&#39;)

{

checkDB();

checkServiceA();

checkRedis();

$server->send(&#39;pong&#39;);

}

});

Copy after login

 

结论

1、tcp的keepalive最简单,但是有兼容性问题,不够灵活

2、swoole提供的keepalive最实用,但是需要客户端配合,复杂度适中

3、应用层的keepalive最灵活但是最麻烦

The above is the detailed content of Summary of common problems with PHP Swoole long connections. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

PHP 8.4 Installation and Upgrade guide for Ubuntu and Debian PHP 8.4 Installation and Upgrade guide for Ubuntu and Debian Dec 24, 2024 pm 04:42 PM

PHP 8.4 brings several new features, security improvements, and performance improvements with healthy amounts of feature deprecations and removals. This guide explains how to install PHP 8.4 or upgrade to PHP 8.4 on Ubuntu, Debian, or their derivati

7 PHP Functions I Regret I Didn't Know Before 7 PHP Functions I Regret I Didn't Know Before Nov 13, 2024 am 09:42 AM

If you are an experienced PHP developer, you might have the feeling that you’ve been there and done that already.You have developed a significant number of applications, debugged millions of lines of code, and tweaked a bunch of scripts to achieve op

How To Set Up Visual Studio Code (VS Code) for PHP Development How To Set Up Visual Studio Code (VS Code) for PHP Development Dec 20, 2024 am 11:31 AM

Visual Studio Code, also known as VS Code, is a free source code editor — or integrated development environment (IDE) — available for all major operating systems. With a large collection of extensions for many programming languages, VS Code can be c

Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Explain JSON Web Tokens (JWT) and their use case in PHP APIs. Apr 05, 2025 am 12:04 AM

JWT is an open standard based on JSON, used to securely transmit information between parties, mainly for identity authentication and information exchange. 1. JWT consists of three parts: Header, Payload and Signature. 2. The working principle of JWT includes three steps: generating JWT, verifying JWT and parsing Payload. 3. When using JWT for authentication in PHP, JWT can be generated and verified, and user role and permission information can be included in advanced usage. 4. Common errors include signature verification failure, token expiration, and payload oversized. Debugging skills include using debugging tools and logging. 5. Performance optimization and best practices include using appropriate signature algorithms, setting validity periods reasonably,

How do you parse and process HTML/XML in PHP? How do you parse and process HTML/XML in PHP? Feb 07, 2025 am 11:57 AM

This tutorial demonstrates how to efficiently process XML documents using PHP. XML (eXtensible Markup Language) is a versatile text-based markup language designed for both human readability and machine parsing. It's commonly used for data storage an

PHP Program to Count Vowels in a String PHP Program to Count Vowels in a String Feb 07, 2025 pm 12:12 PM

A string is a sequence of characters, including letters, numbers, and symbols. This tutorial will learn how to calculate the number of vowels in a given string in PHP using different methods. The vowels in English are a, e, i, o, u, and they can be uppercase or lowercase. What is a vowel? Vowels are alphabetic characters that represent a specific pronunciation. There are five vowels in English, including uppercase and lowercase: a, e, i, o, u Example 1 Input: String = "Tutorialspoint" Output: 6 explain The vowels in the string "Tutorialspoint" are u, o, i, a, o, i. There are 6 yuan in total

Explain late static binding in PHP (static::). Explain late static binding in PHP (static::). Apr 03, 2025 am 12:04 AM

Static binding (static::) implements late static binding (LSB) in PHP, allowing calling classes to be referenced in static contexts rather than defining classes. 1) The parsing process is performed at runtime, 2) Look up the call class in the inheritance relationship, 3) It may bring performance overhead.

What are PHP magic methods (__construct, __destruct, __call, __get, __set, etc.) and provide use cases? What are PHP magic methods (__construct, __destruct, __call, __get, __set, etc.) and provide use cases? Apr 03, 2025 am 12:03 AM

What are the magic methods of PHP? PHP's magic methods include: 1.\_\_construct, used to initialize objects; 2.\_\_destruct, used to clean up resources; 3.\_\_call, handle non-existent method calls; 4.\_\_get, implement dynamic attribute access; 5.\_\_set, implement dynamic attribute settings. These methods are automatically called in certain situations, improving code flexibility and efficiency.

See all articles