Artikel ini akan membawa anda menerokai soket PHP buat kali pertama, dan mempelajari tentang soket dengan membuat pelayan soket mudah saya harap ia akan membantu anda!
Nama Cina soket ialah soket, iaitu "enkapsulasi" TCP/IP. Pada hakikatnya, rangkaian sebenarnya hanya mempunyai empat lapisan, iaitu lapisan aplikasi, lapisan pengangkutan, lapisan rangkaian dan lapisan pautan data dari atas ke bawah. Protokol http yang paling biasa digunakan ialah protokol kepunyaan lapisan aplikasi, dan soket boleh difahami secara ringkas dan kasar sebagai sesuatu lapisan pengangkutan. Jika masih sukar untuk difahami, maka tambah tcp://218.221.11.23:9999 lebih kasar, adakah anda melihatnya? Ini ialah soket tcp.
Soket memberi kita keupayaan untuk mengawal lapisan pengangkutan dan lapisan rangkaian, dengan itu memperoleh prestasi yang lebih kukuh dan kecekapan yang lebih tinggi adalah penyelesaian yang paling biasa digunakan dan matang untuk menyelesaikan pelayan rangkaian konkurensi tinggi. Mana-mana pengaturcara pelayan harus menguasai kemahiran berkaitan pengaturcaraan soket.
Dalam PHP, terdapat dua set fungsi yang boleh mengawal soket Satu ialah soket_ siri fungsi, dan satu lagi ialah siri fungsi_. Socket_ dilaksanakan oleh PHP menyalin terus soket dalam bahasa C, manakala sistem stream_ menggunakan konsep aliran untuk merangkumnya. Mari gunakan fungsi siri socket_* untuk memulakan siri artikel ini sahaja.
Mula-mula buat pelayan soket yang paling mudah:
<?php $host = '0.0.0.0'; $port = 9999; // 创建一个tcp socket $listen_socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); // 将socket bind到IP:port上 socket_bind( $listen_socket, $host, $port ); // 开始监听socket socket_listen( $listen_socket ); // 进入while循环,不用担心死循环死机,因为程序将会阻塞在下面的socket_accept()函数上 while( true ){ // 此处将会阻塞住,一直到有客户端来连接服务器。阻塞状态的进程是不会占据CPU的 // 所以你不用担心while循环会将机器拖垮,不会的 $connection_socket = socket_accept( $listen_socket ); // 向客户端发送一个helloworld $msg = "helloworld\r\n"; socket_write( $connection_socket, $msg, strlen( $msg ) ); socket_close( $connection_socket ); } socket_close( $listen_socket );
Simpan fail sebagai server.php, dan kemudian laksanakan php server.php untuk menjalankannya. Kita boleh menggunakan telnet pada klien Buka terminal lain dan jalankan telnet 127.0.0.1 9999 dan tekan Enter. Keputusan yang dijalankan adalah seperti berikut:
Analisis ringkas kod di atas untuk menggambarkan proses pelayan soket tcp:
Dalam kes di atas, terdapat dua kelemahan besar:
Setelah menganalisis masalah di atas, saya memikirkan pelbagai proses yang disebutkan tadi Kemudian kita boleh membuat proses anak untuk mengendalikan permintaan pelanggan selepas accpet menerima permintaan, supaya apabila menerima Selepas dua. pelanggan, buat proses kanak-kanak untuk menangani permintaan pelanggan kedua. Tidakkah masalah itu dapat diselesaikan? OK! Mari tunjukkan kod:
<?php $host = '0.0.0.0'; $port = 9999; // 创建一个tcp socket $listen_socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); // 将socket bind到IP:port上 socket_bind( $listen_socket, $host, $port ); // 开始监听socket socket_listen( $listen_socket ); // 进入while循环,不用担心死循环死机,因为程序将会阻塞在下面的socket_accept()函数上 while( true ){ // 此处将会阻塞住,一直到有客户端来连接服务器。阻塞状态的进程是不会占据CPU的 // 所以你不用担心while循环会将机器拖垮,不会的 $connection_socket = socket_accept( $listen_socket ); // 当accept了新的客户端连接后,就fork出一个子进程专门处理 $pid = pcntl_fork(); // 在子进程中处理当前连接的请求业务 if( 0 == $pid ){ // 向客户端发送一个helloworld $msg = "helloworld\r\n"; socket_write( $connection_socket, $msg, strlen( $msg ) ); // 休眠5秒钟,可以用来观察时候可以同时为多个客户端提供服务 echo time().' : a new client'.PHP_EOL; sleep( 5 ); socket_close( $connection_socket ); exit; } } socket_close( $listen_socket );
Simpan kod sebagai server.php, dan kemudian laksanakan php server.php Pelanggan masih menggunakan telnet 127.0.0.1 9999, tetapi kali ini kami membuka dua terminal untuk melaksanakan telnet. . Adalah penting untuk diperhatikan bahawa selepas pelanggan pertama menyambung, pelanggan kedua juga boleh menyambung. Keputusan yang dijalankan adalah seperti berikut:
Dengan menerima cap masa permintaan pelanggan, anda boleh melihat bahawa pelayan kini boleh melayani N pelanggan pada masa yang sama. Tetapi, kemudian fikirkan, bagaimana jika 10,000 pelanggan datang untuk meminta? Pada masa ini, pelayan akan menghentikan 10,000 proses kanak-kanak untuk mengendalikan setiap sambungan pelanggan, yang akan membunuh orang. Fork sendiri adalah panggilan sistem yang membazirkan sumber sistem sudah cukup untuk menyebabkan sistem itu ranap Walaupun sistem boleh menahan 1,000 garpu, 1,000 proses anak yang keluar dari garpu sudah cukup untuk meminum seperiuk memori sistem. . Pada akhirnya, adakah ia boleh? Proses anak yang mudah dikeluarkan akan ditutup selepas memproses klien semasa, dan ia perlu dicabang semula untuk permintaan seterusnya kepada nilai sosialis arus perdana. Jika terdapat serangan berniat jahat, bilangan garpu sistem akan meningkat secara linear sehingga sistem ranap.
Jadi, kami sekali lagi mencadangkan penyelesaian yang dipertingkatkan. Kami boleh menganggarkan jumlah perniagaan, dan kemudian menambah bilangan proses anak yang tetap apabila perkhidmatan dimulakan dalam gelung tak terhingga dan disekat apabila sambungan pelanggan masuk, permintaan pelanggan diproses selesai, sambungan hanya ditutup tetapi tidak dimusnahkan, tetapi terus menunggu permintaan pelanggan seterusnya. Dengan cara ini, ia bukan sahaja mengelakkan pembaziran besar sumber yang disebabkan oleh garpu berulang proses, tetapi juga melindungi sistem daripada ranap akibat garpu tak terhingga melalui bilangan proses kanak-kanak yang tetap.
<?php $host = '0.0.0.0'; $port = 9999; // 创建一个tcp socket $listen_socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP ); // 将socket bind到IP:port上 socket_bind( $listen_socket, $host, $port ); // 开始监听socket socket_listen( $listen_socket ); // 给主进程换个名字 cli_set_process_title( 'phpserver master process' ); // 按照数量fork出固定个数子进程 for( $i = 1; $i <= 10; $i++ ){ $pid = pcntl_fork(); if( 0 == $pid ){ cli_set_process_title( 'phpserver worker process' ); while( true ){ $conn_socket = socket_accept( $listen_socket ); $msg = "helloworld\r\n"; socket_write( $conn_socket, $msg, strlen( $msg ) ); socket_close( $conn_socket ); } } } // 主进程不可以退出,代码演示比较粗暴,为了不保证退出直接走while循环,休眠一秒钟 // 实际上,主进程真正该做的应该是收集子进程pid,监控各个子进程的状态等等 while( true ){ sleep( 1 ); } socket_close( $connection_socket );
Selepas menyimpan fail sebagai server.php, jalankan php server.php, dan kemudian gunakan ps -ef | grep phpserver | >
Anda dapat melihat bahawa proses induk wujud Selain itu, terdapat 10 sub-proses menunggu untuk perkhidmatan. Mari cuba melalui telnet 127.0.0.1 9999. Hasil larian adalah seperti berikut:
Baiklah, siri perjalanan baharu PHP akan bermula dengan pengenalan ringkas La! Artikel seterusnya akan menerangkan beberapa asas teori yang lebih mendalam.
Pembelajaran yang disyorkan: "Tutorial Video PHP"
Atas ialah kandungan terperinci Pembelajaran soket PHP: membawa anda membuat pelayan soket mudah. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!