ホームページ  >  記事  >  バックエンド開発  >  PHP SOCKETプログラミングの詳しい解説_PHPチュートリアル

PHP SOCKETプログラミングの詳しい解説_PHPチュートリアル

WBOY
WBOYオリジナル
2016-07-13 09:52:58804ブラウズ

PHP SOCKETプログラミングの詳細な説明

この記事では主にPHP SOCKETプログラミングの詳細な説明を紹介していますので、必要な方は参考にしてください

1.予備知識

PHP のソケット モジュールを使用して何かを行う人はあまり見かけませんが、おそらく誰もがそれをスクリプト言語の範囲内に置いていますが、実際には PHP のソケット モジュールは、ftplist、http ポスト送信、smtp 送信など、多くのことを行うことができます。 、パケットのグループ化と特別なメッセージの相互作用 (smpp プロトコルなど)、whois クエリ。これらは比較的一般的なクエリです。

特に、PHP のソケット拡張ライブラリでできることは、C よりもそれほど劣っていません。

phpソケット接続関数

1. カーネルに統合されたソケット

この一連の機能はアクティブな接続のみを実行でき、ポート監視関連の機能は実装できません。 4.3.0 より前では、すべてのソケット接続はブロッキング モードでのみ機能します。

この一連の機能には以下が含まれます

fsockopen、pfsockopen

これら 2 つの関数に関する特別な情報は、php.net のユーザー マニュアルに記載されています

これらはすべてリソース番号を返します。このリソースでは、fgets()、fwrite()、fclose() など、ファイルを操作するほぼすべての関数を使用できます。すべての関数がネットワークに直面するためにこれらの関数に従うことに注意してください。フロー パターンの例:

fread() はファイル ポインタ ハンドルから最大 length バイトを読み取ります。 この関数は、length バイトを読み取った後、EOF に達したとき、または (ネットワーク ストリームの場合) パケットが利用可能になったときのいずれかが早い時点で、ファイルの読み取りを停止します。

ネットワークフローの場合、完全なパケットが取得された時点で停止することに注意を払う必要があることがわかります。

2. php拡張モジュールが提供するソケット関数。

php4.xではextension=php_sockets.dll、Linuxではextension=php_sockets.soというモジュールが存在します。

このモジュールがオンになっている場合、PHP には、リッスン ポート、ブロッキング モードと非ブロッキング モードの切り替え、マルチクライアントの対話型処理などを含む強力なソケット機能があることを意味します。

このシリーズの関数のリストについては、http://www.php.net/manual/en/ref.sockets.phpを参照してください

このリストを読んだ後、これは非常に充実していると思いますか? しかし、このモジュールがまだ非常に未熟で、関連する参考資料がほとんどないのは残念です: (

私も研究中なので、今回は詳しくは触れませんが、参考記事として紹介します

http://www.zend.com/pecl/tutorials/sockets.php

2. PHPソケット拡張機能を使用する

サーバー側コード:

?

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

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

/**

* ファイル名server.php

* サーバー側のコード

*

* @著者 guisu.huang

* @2012-04-11 以降

*

*/

//クライアントへの接続時にタイムアウトがないことを確認します

set_time_limit(0);

//IPとポート番号を設定します

$アドレス = "127.0.0.1";

$port = 2046; //デバッグ時に、プログラムをテストするためにさらに多くのポートを変更できます。

/**

* ソケットを作成します

* AF_INET= は ipv4 です。ipv6 が使用される場合、パラメーターは AF_INET6 です。

* SOCK_STREAM はソケットの TCP タイプです。UDP の場合は SOCK_DGRAM を使用します。

*/

$sock =ソケット_create(AF_INET, SOCK_STREAM, SOL_TCP) または die("socket_create() 失敗の理由は次のとおりです:" .socket_strerror(socket_last_error()) ."/n");

//ブロックモード

socket_set_block($sock) または die("socket_set_block() は次の理由で失敗しました:" .socket_strerror(socket_last_error()) . "/n");

//ソケットポートにバインド

$result =socket_bind($sock, $address, $port) または die("socket_bind() 失敗の理由は次のとおりです:" .socket_strerror(socket_last_error()) . "/n");

//監視を開始します

$result =socket_listen($sock, 4) または die("socket_listen() 失敗の理由は次のとおりです:" .socket_strerror(socket_last_error()) . "/n");

echo "$address:$port でソケットを OKnBinding ... ";

echo "OKn接続を受け入れる準備ができました。nソケットでリッスンしています...n";

do { // デーモンを決して停止しないでください

//接続リクエストを受信し、サブ接続ソケットを呼び出してクライアントとサーバー間の情報を処理します

$msgsock =socket_accept($sock) または die("socket_accept() が失敗しました: 理由: " .socket_strerror(socket_last_error()) . "/n");

//クライアントデータを読み取る

echo "クライアント データ n を読み取ります";

//socket_read 関数は、n、t、または

$buf =ソケット_読み取り($msgsock, 8192);

echo "受信したメッセージ: $buf n";

//データ送信はクライアントに戻り結果を書き込みます

$msg = "ようこそ";

socket_write($msgsock, $msg, strlen($msg)) または die("socket_write() が失敗しました: 理由: " .socket_strerror(socket_last_error()) ."/n");

//出力がクライアントに返されたら、socket_close($msgsock) 関数を通じて親/子ソケットを終了する必要があります

socket_close($msgsock);

} while (true);

socket_close($sock);

クライアントコード:

?

cli を使用してサーバーを起動します:

phpserver.php

ここでsocket_read関数に注目してください:

オプションの型パラメータは名前付き定数です:

PHP_BINARY_READ - システムのrecv()関数を使用します。バイナリデータの読み取りに対するセキュリティ。 (PHP の場合>「デフォルト = 4.1.0)」

PHP_NORMAL_READ - 読み取りは n または r で停止します (PHP <= 4.0.6 のデフォルト)

パラメータPHP_NORMAL_READの場合、サーバーの応答結果にnが無い場合。原因socket_read(): ソケットから読み取ることができません

3. PHPソケットの内部ソースコード

PHPの内部ソースコードから判断すると、PHPが提供するソケットプログラミングは、ソケット、バインド、リッスンなどの機能にレイヤーを追加し、よりシンプルで呼び出しやすくしています。ただし、一部のビジネス ロジック プログラムは依然としてプログラマー自身が実装する必要があります。

次に、socket_create のソースコード実装を使用して、PHP の内部実装を説明します。

PHP のソケットは拡張された方法で実装されていることを前述しました。ソース コードの ext ディレクトリに、socket ディレクトリがあります。このディレクトリには、PHP のソケット実装が保存されます。 PHP_FUNCTION(socket_create) を直接検索し、socket.c ファイル内でこの関数の実装を見つけます。コードは次のとおりです:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

/**

* ファイル名:client.php

* クライアントコード

*

* @著者 guisu.huang

* @2012-04-11 以降

*/

set_time_limit(0);

$host = "127.0.0.1";

$ポート = 2046;

$socket =ソケット_create(AF_INET, SOCK_STREAM, SOL_TCP)or die("ソケットを作成できませんでした") // ソケットを作成します

;

$connection =socket_connect($socket, $host, $port) または die("サーバーに接続できませんでした") // 接続します

socket_write($socket, "helloソケット") または die("Write failedn") // データ転送によりサーバーにメッセージが送信されます

;

while ($buff =socket_read($socket, 1024, PHP_NORMAL_READ)) {

echo("応答は次のとおりです:" . $buff . "n");

}

socket_close($socket);

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

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

/* {{{ プロトリソースソケット_create(int ドメイン, int 型, int プロトコル) U

domain で指定されたドメイン内に、type */

で指定されたタイプの通信用のエンドポイントを作成します

PHP_FUNCTION(socket_create)

{

long arg1、arg2、arg3;

php_socket *php_sock = (php_socket*)emalloc(sizeof(php_socket));

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "llll", &arg1, &arg2, &arg3) == FAILURE) {

efree(php_sock);

戻る;

}

if (arg1 != AF_UNIX

#if HAVE_IPV6

&& arg1 != AF_INET6

#endif

&& arg1 != AF_INET) {

php_error_docref(NULL TSRMLS_CC, E_WARNING, "AF_INET を想定し、引数 1 に無効なソケット ドメイン [%ld] が指定されました", arg1);

arg1 = AF_INET;

}

if (arg2 > 10) {

php_error_docref(NULL TSRMLS_CC, E_WARNING, "SOCK_STREAM を想定し、引数 2 に無効なソケット タイプ [%ld] が指定されました", arg2);

arg2 = SOCK_STREAM;

}

php_sock->bsd_socket = ソケット(arg1, arg2, arg3);

php_sock->type = arg1;

if (IS_INVALID_SOCKET(php_sock)) {

SOCKETS_G(last_error) = エラー番号;

php_error_docref(NULL TSRMLS_CC, E_WARNING, "ソケット [%d] を作成できません: %s", errno, php_strerror(errno TSRMLS_CC));

efree(php_sock);

RETURN_FALSE;

}

php_sock->error = 0;

php_sock->ブロック = 1;

1257,1-8 61%

ZEND_REGISTER_RESOURCE(return_value, php_sock, le_socket);

}

Zend API は実際には、PHP で使用するために c 関数ソケットをラップします。 C ソケット プログラミングでは、次のメソッドを使用してソケットを初期化します。

?

1

2

3

4

5

//ソケットを初期化する

if( (socket_fd = ソケット(AF_INET, SOCK_STREAM, 0)) == -1 ){

printf("ソケット作成エラー: %s(errno: %d)n",strerror(errno),errno);

終了(0);

}

4.ソケット関数

関数名の説明

socket_accept() はソケット接続を受け入れます

socket_bind() はソケットを IP アドレスとポートにバインドします

socket_clear_error() ソケットエラーまたは最後のエラーコードをクリアします

socket_close()はソケットリソースを閉じます

socket_connect()はソケット接続を開始します

Socket_create_listen() は、指定されたポートでリッスンするソケットを開きます

Socket_create_pair() は未分化ソケットのペアを配列に生成します

Socket_create() はソケットを生成します。これはソケットのデータ構造を生成するのと同等です

socket_get_option() ソケットオプションを取得します

Socket_getpeername() リモートの同様のホストのIPアドレスを取得します

socket_getsockname() ローカルソケットのIPアドレスを取得します

socket_iovec_add() は、新しいベクトルを分散/集約配列に追加します

socket_iovec_alloc() この関数は、送信、受信、読み取り、書き込みが可能な iovec データ構造を作成します

socket_iovec_delete()は割り当てられたiovecを削除します

socket_iovec_fetch()は、指定されたiovecリソースのデータを返します

socket_iovec_free() は iovec リソースを解放します

Socket_iovec_set()はiovecデータの新しい値を設定します

Socket_last_error() は現在のソケットの最後のエラーコードを取得します

socket_listen() は、指定されたソケットからのすべての接続をリッスンします

Socket_read()は指定された長さのデータを読み込みます

Socket_readv() は分散/集約配列からデータを読み取ります

socket_recv()はソケットからキャッシュへのデータを終了します

Socket_recvfrom() は、指定されたソケットからデータを受け取ります。指定されていない場合、デフォルトで現在のソケットが使用されます。

socket_recvmsg()はiovecからメッセージを受け取ります

socket_select() 複数選択

socket_send() この関数は接続されたソケットにデータを送信します

socket_sendmsg() メッセージをソケットに送信します

socket_sendto() は、指定されたアドレスのソケットにメッセージを送信します

Socket_set_block() はソケットをブロックモードに設定します

Socket_set_nonblock() ソケットをノンブロックモードに設定します

socket_set_option() ソケットオプションを設定します

socket_shutdown() この関数を使用すると、読み取り、書き込み、または指定されたソケットを閉じることができます

socket_strerror()は、指定されたエラー番号を持つ詳細なエラーを返します

socket_write() はソケットキャッシュにデータを書き込みます

socket_writev() は分散/集約配列にデータを書き込みます

5. PHPソケットシミュレーションリクエスト

stream_socket を使用してシミュレートします:

?

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

26

27

28

29

30

31

/**

*

* @param $data= array=array('key'=>value)

*/

関数 post_contents($data = array()) {

$post = $data ? http_build_query($data) : '';

$header = "POST /test/ HTTP/1.1" .

$header .= "ユーザーエージェント: Mozilla/4.0+(互換性;+MSIE+6.0;+Windows+NT+5.1;+SV1)" .

$header .= "ホスト: localhost" .

$header .= "受け入れる: */*" .

$header .= "リファラー: http://localhost/test/" .

$header .= "Content-Length: ".strlen($post) .

$header .= "Content-Type: application/x-www-form-urlencoded" .

$header .= "rn";

$ddd = $header .

$fp = stream_socket_client("tcp://localhost:80", $errno, $errstr, 30);

$response = '';

if (!$fp) {

echo "$errstr ($errno)
n";

} 他 {

fwrite($fp, $ddd);

$i = 1;

while ( !feof($fp) ) {

$r = fgets($fp, 1024);

$response .= $r;

//この行を処理します

}

}

fclose($fp);

$response を返す;

}

上記のプログラムは無限ループに入る可能性があることに注意してください。

PHPのfeof($fp)で注意すべき点ですが、なぜ無限ループに陥るのかを分析してみましょう。

?

1

2

3

4

while ( !feof($fp) ) {

$r = fgets($fp, 1024);

$response .= $r;

}

実際、feof は信頼性がありますが、fgets 関数と組み合わせて使用​​する場合は注意が必要です。一般的なアプローチは次のとおりです:

?

1

2

3

4

5

$fp = fopen("myfile.txt", "r");

ながら (!feof($fp)) {

$current_line = fgets($fp);

// 無限ループに入らないように結果をさらに処理します

}

プレーンテキストを処理する場合、fgets が文字の最後の行を取得した後、foef 関数によって返される結果は TRUE ではありません。実際の操作プロセスは次のとおりです:

1) while() はループし続けます。

2) fgetsは最後から2行目の文字列を取得します

3) feofはfalseを返し、次のループに入る

4) fgets はデータの最後の行を取得します

5) fegets 関数が呼び出されても、feof 関数は false を返します。したがって、ループを実行し続けます

6) fget は別の行を取得しようとしますが、実際の結果は空です。実際のコードはこれを認識せず、存在しない別の行を処理しようとしましたが、fgets が呼び出され、feof put back の結果は false のままでした

7) ……

8) 無限ループに入る

http://www.bkjia.com/PHPjc/1004548.htmlwww.bkjia.com本当http://www.bkjia.com/PHPjc/1004548.html技術記事 PHP SOCKET プログラミングの詳細な説明 この記事では、PHP SOCKET プログラミングの詳細な説明を主に紹介します。必要な友人は、1. 予備知識を参照してください。PHP のソケット モジュールを使用して...
声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。