PHP 네트워크 프로그래밍의 차단 모델 허용 소개
Accept 차단 모델은 비교적 오래된 모델이지만 차단/비차단, 잠금, 시간 제한 재전송 등 흥미로운 지식이 많이 포함되어 있습니다.
서버 프로그램 acceptSever.php
<?php set_time_limit(0); # 设置脚本执行时间无限制 class SocketServer { private static $socket; function SocketServer($port) { global $errno, $errstr; if ($port < 1024) { die("Port must be a number which bigger than 1024/n"); } $socket = stream_socket_server("tcp://0.0.0.0:{$port}", $errno, $errstr); if (!$socket) die("$errstr ($errno)"); while ($conn = stream_socket_accept($socket, -1)) { // 这样设置不超时才有用 static $id = 0; # 进程 id static $ct = 0; # 接收数据的长度 $ct_last = $ct; $ct_data = ''; # 接受的数据 $buffer = ''; # 分段读取数据 $id++; echo "Client $id come" . PHP_EOL; # 持续监听 while (!preg_match('{/r/n}', $buffer)) { // 没有读到结束符,继续读 // if (feof($conn)) break; // 防止 popen 和 fread 的 bug 导致的死循环 $buffer = fread($conn, 1024); echo 'R' . PHP_EOL; # 打印读的次数 $ct += strlen($buffer); $ct_data .= preg_replace('{/r/n}', '', $buffer); } $ct_size = ($ct - $ct_last) * 8; echo "[$id] " . __METHOD__ . " > " . $ct_data . PHP_EOL; fwrite($conn, "Received $ct_size byte data./r/n"); fclose($conn); } fclose($socket); } } new SocketServer(2000);
클라이언트 프로그램 acceptClient. php
<?php # 日志记录 function debug ($msg) { error_log($msg, 3, './socket.log'); } if ($argv[1]) { $socket_client = stream_socket_client('tcp://0.0.0.0:2000', $errno, $errstr, 30); /* 设置脚本为非阻塞 */ # stream_set_blocking($socket_client, 0); /* 设置脚本超时时间 */ # stream_set_timeout($socket_client, 0, 100000); if (!$socket_client) { die("$errstr ($errno)"); } else { # 填充容器 $msg = trim($argv[1]); for ($i = 0; $i < 10; $i++) { $res = fwrite($socket_client, "$msg($i)"); usleep(100000); echo 'W'; // 打印写的次数 # debug(fread($socket_client, 1024)); // 将产生死锁,因为 fread 在阻塞模式下未读到数据时将等待 } fwrite($socket_client, "/r/n"); // 传输结束符 # 记录日志 debug(fread($socket_client, 1024)); fclose($socket_client); } } else { // $phArr = array(); // for ($i = 0; $i < 10; $i++) { // $phArr[$i] = popen("php ".__FILE__." '{$i}:test'", 'r'); // } // foreach ($phArr as $ph) { // pclose($ph); // } for ($i = 0; $i < 10; $i++) { system("php ".__FILE__." '{$i}:test'"); # 这里等于 php "当前文件" "脚本参数" } }
코드 분석
먼저 위의 코드 논리를 설명하세요. 클라이언트 acceptClient.php는 루프에서 데이터를 보내고 마지막으로 서버에 종료자를 보냅니다. Accept Server.php는 수락 차단 방법을 사용하여 소켓 연결을 받습니다. 그런 다음 종료자가 수신될 때까지 수신 데이터를 반복하고 결과 데이터(수신된 바이트 수)를 반환합니다. 클라이언트는 서버에서 반환된 데이터를 수신하여 로그에 기록합니다. 논리는 매우 간단하지만 분석할 가치가 있는 몇 가지 상황이 있습니다.
A> 기본적으로 php 소켓_client.php 테스트를 실행할 때 클라이언트는 10W를 인쇄하고 서버는 여러 R을 인쇄한 다음 수신된 데이터를 인쇄합니다. 소켓.log는 서버가 반환한 수신 결과 데이터를 기록하며, 그 효과는 다음과 같습니다.
이 상황은 이해하기 쉬우므로 자세히 설명하지 않습니다. 그런 다음 telnet 명령을 사용하여 동시에 여러 클라이언트를 엽니다. 그림에 표시된 대로 서버는 한 번에 하나의 클라이언트만 처리합니다.
다른 클라이언트는 이 뒤에 "대기"해야 합니다. IO를 차단하는 특성이 있습니다. 이 모델의 약점은 명백하며 효율성이 매우 낮습니다.
B> 소켓_client.php의 29번째 줄에 있는 주석 코드만 열고 php 소켓_client.php 테스트를 다시 실행하세요. 클라이언트는 W를 출력하고 서버도 R을 출력합니다. 그 후 두 프로그램 모두 중단됩니다. 그 이유는 논리를 분석한 후에 클라이언트가 종결자를 보내기 전에 서버에 데이터를 반환하기를 원하고 서버가 종결자를 수신하지 않았기 때문에 클라이언트에게도 종결자를 요청하기 때문이라는 것을 알 수 있습니다. 교착 상태를 유발합니다. W와 R 하나만 입력하는 이유는 fread가 기본적으로 차단되기 때문입니다. 이 교착 상태를 해결하려면 소켓_client.php의 17번째 줄에서 주석 코드를 열고 소켓에 대해 timeout을 0.1초로 설정해야 합니다. 다시 실행하면 W와 R이 0.1초마다 나타나는 것을 볼 수 있습니다. 그러면 정상적으로 종료되고 서버는 반환합니다. 수신 결과 데이터도 정상적으로 기록됩니다. fread가 기본적으로 차단되는 것을 볼 수 있습니다. 프로그래밍 시 특별한 주의가 필요합니다. 시간 초과가 설정되지 않으면 교착 상태가 쉽게 발생합니다.
C> 14줄의 주석만 열고 스크립트를 비차단으로 설정합니다. php 소켓_client.php 테스트를 실행합니다. 결과는 기본적으로 사례 A와 동일합니다. 유일한 차이점은 소켓.log가 반환을 기록하지 않는다는 것입니다. non-blocking을 실행하면 클라이언트가 서버의 응답 결과를 기다리지 않고 실행을 계속할 수 있기 때문입니다. 디버그가 실행될 때 읽기 데이터는 여전히 비어 있으므로 소켓.log도 비어 있습니다. 여기서는 차단 모드와 비차단 모드에서 실행되는 클라이언트의 차이점을 볼 수 있습니다. 물론 클라이언트가 결과 수락에 관심이 없는 경우 비차단 모드를 사용하여 최대 효율성을 얻을 수 있습니다.
D> php 소켓_client.php를 실행하면 위의 로직을 10번 연속으로 실행하게 됩니다. 여기에는 아무런 문제가 없지만 매우 이상한 점은 39-45줄의 코드를 사용하고 10개의 프로세스를 열면 된다는 것입니다. 동시에 서버 측의 무한 루프가 매우 이상해집니다! 나중에 조사 결과, popen으로 열린 프로세스에 의해 생성된 연결로 인해 fread 또는 소켓_read가 오류를 일으키고 빈 문자열을 직접 반환하여 무한 루프가 발생하는 한, PHP 소스 코드를 확인한 후 발견되었습니다. PHP의 popen 및 fread 함수는 C에 전혀 고유하지 않은 것으로 나타났으며, 여기에는 많은 양의 php_stream_* 구현 논리가 삽입되어 있으며 이는 내부 버그로 인한 소켓 연결 중단으로 인해 발생하는 것으로 추정됩니다. 해결 방법은 Socket_server.php에서 33줄의 코드를 여는 것입니다. 연결이 중단되면 루프에서 빠져나오지만 이렇게 하면 많은 데이터가 손실되므로 이 문제는 특별한 주의가 필요합니다!
관련 권장 사항:
PHP 정규 표현식이란 무엇입니까? PHP 정규식 사용 방법(코드 포함)
위 내용은 PHP 네트워크 프로그래밍의 차단 모델 허용 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











PHP 8.4는 상당한 양의 기능 중단 및 제거를 통해 몇 가지 새로운 기능, 보안 개선 및 성능 개선을 제공합니다. 이 가이드에서는 Ubuntu, Debian 또는 해당 파생 제품에서 PHP 8.4를 설치하거나 PHP 8.4로 업그레이드하는 방법을 설명합니다.

VS Code라고도 알려진 Visual Studio Code는 모든 주요 운영 체제에서 사용할 수 있는 무료 소스 코드 편집기 또는 통합 개발 환경(IDE)입니다. 다양한 프로그래밍 언어에 대한 대규모 확장 모음을 통해 VS Code는

숙련된 PHP 개발자라면 이미 그런 일을 해왔다는 느낌을 받을 것입니다. 귀하는 상당한 수의 애플리케이션을 개발하고, 수백만 줄의 코드를 디버깅하고, 여러 스크립트를 수정하여 작업을 수행했습니다.

이 튜토리얼은 PHP를 사용하여 XML 문서를 효율적으로 처리하는 방법을 보여줍니다. XML (Extensible Markup Language)은 인간의 가독성과 기계 구문 분석을 위해 설계된 다목적 텍스트 기반 마크 업 언어입니다. 일반적으로 데이터 저장 AN에 사용됩니다

JWT는 주로 신분증 인증 및 정보 교환을 위해 당사자간에 정보를 안전하게 전송하는 데 사용되는 JSON을 기반으로 한 개방형 표준입니다. 1. JWT는 헤더, 페이로드 및 서명의 세 부분으로 구성됩니다. 2. JWT의 작업 원칙에는 세 가지 단계가 포함됩니다. JWT 생성, JWT 확인 및 Parsing Payload. 3. PHP에서 인증에 JWT를 사용하면 JWT를 생성하고 확인할 수 있으며 사용자 역할 및 권한 정보가 고급 사용에 포함될 수 있습니다. 4. 일반적인 오류에는 서명 검증 실패, 토큰 만료 및 대형 페이로드가 포함됩니다. 디버깅 기술에는 디버깅 도구 및 로깅 사용이 포함됩니다. 5. 성능 최적화 및 모범 사례에는 적절한 시그니처 알고리즘 사용, 타당성 기간 설정 합리적,

문자열은 문자, 숫자 및 기호를 포함하여 일련의 문자입니다. 이 튜토리얼은 다른 방법을 사용하여 PHP의 주어진 문자열의 모음 수를 계산하는 방법을 배웁니다. 영어의 모음은 A, E, I, O, U이며 대문자 또는 소문자 일 수 있습니다. 모음이란 무엇입니까? 모음은 특정 발음을 나타내는 알파벳 문자입니다. 대문자와 소문자를 포함하여 영어에는 5 개의 모음이 있습니다. a, e, i, o, u 예 1 입력 : String = "Tutorialspoint" 출력 : 6 설명하다 문자열의 "Tutorialspoint"의 모음은 u, o, i, a, o, i입니다. 총 6 개의 위안이 있습니다

정적 바인딩 (정적 : :)는 PHP에서 늦은 정적 바인딩 (LSB)을 구현하여 클래스를 정의하는 대신 정적 컨텍스트에서 호출 클래스를 참조 할 수 있습니다. 1) 구문 분석 프로세스는 런타임에 수행됩니다. 2) 상속 관계에서 통화 클래스를 찾아보십시오. 3) 성능 오버 헤드를 가져올 수 있습니다.

PHP의 마법 방법은 무엇입니까? PHP의 마법 방법은 다음과 같습니다. 1. \ _ \ _ Construct, 객체를 초기화하는 데 사용됩니다. 2. \ _ \ _ 파괴, 자원을 정리하는 데 사용됩니다. 3. \ _ \ _ 호출, 존재하지 않는 메소드 호출을 처리하십시오. 4. \ _ \ _ get, 동적 속성 액세스를 구현하십시오. 5. \ _ \ _ Set, 동적 속성 설정을 구현하십시오. 이러한 방법은 특정 상황에서 자동으로 호출되어 코드 유연성과 효율성을 향상시킵니다.
