きょろきょろ(๑´• ₃ •̀๑)

特にWeb系についてのことを書いていきたいと思います。 基本的にメモ書きみたいなものです。

PHPでソケット通信(UDP)

今回、PHPでソケット通信を行いました。
環境としては、C言語でクライアント側(UDPを送る)を行い、PHPでサーバ側を行うというものでした。今回C言語のクライアント側は元々あるものとし、PHP側のサーバを作成しました。作成したPHPのコードを以下に示します。

<?php
	class packet_format{
		public $type;
		public $message;
		public $recv_date;
	}
	
	$recv_data = new packet_format;
	$port = 5050;

	//UDPのソケット作成
	$sock = socket_create(AF_INET,SOCK_DGRAM,SOL_UDP);
	socket_bind($sock,'127.0.0.1',$port);
	$from = '';
	while(true){
		//UDPのソケットを受信
		socket_recvfrom($sock,$buf,4096,0,$from,$port);
		//バイナリで取得しているため、unpackでデータを取得
		$packet_data = unpack("Stype/Smessage/ITimestamp",$buf);
		
		//対応する変数に代入
		$recv_data->type = $array["type"];
		$recv_data->message = $array["message"];
		$recv_data->recv_date = date('D M d H:i:s Y',$array["Timestamp"]);
		/*
			確認応答パケットをUDPで送信(データは1,2,3,4)
			送るデータをpackでバイナリ文字列にパックした後送る
		*/
		$socket = socket_create(AF_INET,SOCK_DGRAM,SOL_UDP);
		$sock_data = pack('SSSS',1,2,3,4);
		socket_sendto($socket,$sock_data,strlen($sock_data),0,$from,$port);
	}
	//close socket
	socket_close($sock);
        socket_close($socket);
?>

今回の場合はサーバを作成しているため、while文で常に起動させておきます。

UDPのソケットの受信の順序

  • socket_create関数で受信ソケットの作成
  • socket_bind関数でソケットに名前を付ける
  • socket_recvfrom関数でソケットの受信待ち
  • unpack関数でソケットのバイナリデータを解析
  • socket_close関数でソケットを閉じる

UDPの場合はソケットを作成する際に、socket_create関数の第2,3引数には、SOCK_DGRAMとSOL_UDPを指定する。TCPでは、SOCK_DGRAM→SOCK_STREAMで、SOL_UDP→SOL_TCPで行けると思います。
次に、bindでソケットに名前を付けた後、socket_recvfromでパケットの受信を行います。受信後の引数である$fromと$portには、ソケットの送信者のIPアドレスとポート番号の情報が入るみたいです。

次に、受信したバイナリデータ(ソケットからのデータ)をそのままデータとして取得はできませんので、unpack関数を利用し、それぞれのデータとして分解します。戻り値としては、配列として返却します。
unpack関数では、

<?php
    unpack("Stype",$buf);  //array("type"=>Sのデータ);
?>

のように使うのですが、Sは、データのフォーマットでありtypeは、連想配列のkeyの名前となります。

<?php
    unpack("S",$buf);  //array("1"=>Sのデータ);
?>

でも良いのですが、この場合では、配列の添え字が1から始まります。
データのフォーマットについては、送信の際にpack関数を用いるのですが、その時に指定したフォーマットを同様にunpackで指定するとよいと思います。
PHP: pack - Manual
ここにデータのフォーマットが書かれています。

そして、最後はsocket_closeでソケットを閉じておしまいです。