PHPでは、ソケットベースの双方向通信は一般的なネットワークプログラミングタスクです。効率的なメッセージングに関しては、2つの関数socket_sendmsgとsocket_recvmsgは、開発者がより柔軟で複雑な通信モードを達成できるように、より高度な関数を提供できます。この記事では、 socket_recvmsgを使用してsocket_sendmsgを使用して双方向通信を実現する方法について説明します。
まず、これら2つの機能の基本的な使用を理解する必要があります。
socket_sendmsg :この関数は、指定されたソケットにデータを送信するために使用され、追加のフラグ、制御情報、または添付ファイルデータを渡すことができます。 ITとsocket_sendの主な違いは、 socket_sendmsgがより強力な柔軟性を提供し、より複雑なデータ構造をサポートできることです。
socket_recvmsg :この関数は、ソケットからメッセージを受信するために使用されます。受信できるメッセージにはデータが含まれているだけでなく、 Socket_Recvと比較して、送信者のアドレス、データメタデータなどの制御情報が含まれている場合があります。より多くの通信情報を返すことができ、双方向通信がより柔軟になります。
実際のアプリケーションでは、双方向のコミュニケーションは、多くの場合、両当事者がお互いからデータを送信して受信できる必要があることを意味します。 socket_sendmsgおよびsocket_recvmsgを使用すると、これを効率的に達成できます。これらの2つの機能は、メッセージヘッダーとデータパーツを制御することにより、より柔軟に相互作用できます。
まず、通常はSocket_Create関数を介してソケットを初期化して、TCPまたはUDPタイプのソケットを作成する必要があります。次に、バインディングまたは接続にsocket_bindまたはsocket_connectを使用できます。
<span><span><span class="hljs-comment">// 作成する Socket</span></span><span>
</span><span><span class="hljs-variable">$socket</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_create</span></span><span>(AF_INET, SOCK_STREAM, SOL_TCP);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$socket</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"Socket 作成する失败: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>());
</span><span><span class="hljs-keyword">exit</span></span><span>();
}
</span><span><span class="hljs-comment">// サーバーに接続します</span></span><span>
</span><span><span class="hljs-variable">$address</span></span><span> = </span><span><span class="hljs-string">'127.0.0.1'</span></span><span>;
</span><span><span class="hljs-variable">$port</span></span><span> = </span><span><span class="hljs-number">8080</span></span><span>;
</span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_connect</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>, </span><span><span class="hljs-variable">$address</span></span><span>, </span><span><span class="hljs-variable">$port</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$result</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"接続に失敗しました: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>());
</span><span><span class="hljs-keyword">exit</span></span><span>();
}
</span></span>
socket_sendmsg関数を使用すると、複雑なデータ構造を含むメッセージを送信できます。通常、追加の制御情報を含むことができるMSGHDR構造にデータをカプセル化します。たとえば、送信されたフラグビット、追加データ、宛先アドレスなどを指定します。
<span><span><span class="hljs-variable">$msg</span></span><span> = </span><span><span class="hljs-string">"Hello, Server!"</span></span><span>;
</span><span><span class="hljs-variable">$len</span></span><span> = </span><span><span class="hljs-title function_ invoke__">strlen</span></span><span>(</span><span><span class="hljs-variable">$msg</span></span><span>);
</span><span><span class="hljs-comment">// 作成する一个消息头</span></span><span>
</span><span><span class="hljs-variable">$msgHdr</span></span><span> = </span><span><span class="hljs-keyword">array</span></span><span>(
</span><span><span class="hljs-string">'msg_name'</span></span><span> => </span><span><span class="hljs-literal">null</span></span><span>, </span><span><span class="hljs-comment">// デフォルトの宛先アドレスは空です</span></span><span>
</span><span><span class="hljs-string">'msg_namelen'</span></span><span> => </span><span><span class="hljs-number">0</span></span><span>,
</span><span><span class="hljs-string">'msg_iov'</span></span><span> => </span><span><span class="hljs-keyword">array</span></span><span>(</span><span><span class="hljs-keyword">array</span></span><span>(</span><span><span class="hljs-string">'iov_base'</span></span><span> => </span><span><span class="hljs-variable">$msg</span></span><span>, </span><span><span class="hljs-string">'iov_len'</span></span><span> => </span><span><span class="hljs-variable">$len</span></span><span>)), </span><span><span class="hljs-comment">// データコンテンツ</span></span><span>
</span><span><span class="hljs-string">'msg_iovlen'</span></span><span> => </span><span><span class="hljs-number">1</span></span><span>,
</span><span><span class="hljs-string">'msg_control'</span></span><span> => </span><span><span class="hljs-literal">null</span></span><span>,
</span><span><span class="hljs-string">'msg_controllen'</span></span><span> => </span><span><span class="hljs-number">0</span></span><span>,
</span><span><span class="hljs-string">'msg_flags'</span></span><span> => </span><span><span class="hljs-number">0</span></span><span>
);
</span><span><span class="hljs-comment">// メッセージを送信します</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">socket_sendmsg</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>, </span><span><span class="hljs-variable">$msgHdr</span></span><span>) === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"失敗した送信: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>());
</span><span><span class="hljs-keyword">exit</span></span><span>();
}
</span></span>
socket_recvmsg関数はsocket_sendmsgに反しており、ソケットから複雑なデータを含むメッセージを受信するために使用されます。データ部分に加えて、返品するメッセージには、送信者のアドレス、ロゴ、その他の情報が含まれる場合があります。
<span><span><span class="hljs-comment">// メッセージを受信する準備をするバッファー</span></span><span>
</span><span><span class="hljs-variable">$buf</span></span><span> = </span><span><span class="hljs-string">""</span></span><span>;
</span><span><span class="hljs-variable">$bufLen</span></span><span> = </span><span><span class="hljs-number">1024</span></span><span>;
</span><span><span class="hljs-variable">$msgHdrRecv</span></span><span> = </span><span><span class="hljs-keyword">array</span></span><span>(
</span><span><span class="hljs-string">'msg_name'</span></span><span> => </span><span><span class="hljs-literal">null</span></span><span>,
</span><span><span class="hljs-string">'msg_namelen'</span></span><span> => </span><span><span class="hljs-number">0</span></span><span>,
</span><span><span class="hljs-string">'msg_iov'</span></span><span> => </span><span><span class="hljs-keyword">array</span></span><span>(</span><span><span class="hljs-keyword">array</span></span><span>(</span><span><span class="hljs-string">'iov_base'</span></span><span> => &</span><span><span class="hljs-variable">$buf</span></span><span>, </span><span><span class="hljs-string">'iov_len'</span></span><span> => </span><span><span class="hljs-variable">$bufLen</span></span><span>)),
</span><span><span class="hljs-string">'msg_iovlen'</span></span><span> => </span><span><span class="hljs-number">1</span></span><span>,
</span><span><span class="hljs-string">'msg_control'</span></span><span> => </span><span><span class="hljs-literal">null</span></span><span>,
</span><span><span class="hljs-string">'msg_controllen'</span></span><span> => </span><span><span class="hljs-number">0</span></span><span>,
</span><span><span class="hljs-string">'msg_flags'</span></span><span> => </span><span><span class="hljs-number">0</span></span><span>
);
</span><span><span class="hljs-comment">// メッセージを受信します</span></span><span>
</span><span><span class="hljs-variable">$bytesReceived</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_recvmsg</span></span><span>(</span><span><span class="hljs-variable">$socket</span></span><span>, </span><span><span class="hljs-variable">$msgHdrRecv</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$bytesReceived</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"受信失敗: "</span></span><span> . </span><span><span class="hljs-title function_ invoke__">socket_strerror</span></span><span>(</span><span><span class="hljs-title function_ invoke__">socket_last_error</span></span><span>());
</span><span><span class="hljs-keyword">exit</span></span><span>();
}
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"メッセージを受け取りました: "</span></span><span> . </span><span><span class="hljs-variable">$buf</span></span><span> . </span><span><span class="hljs-string">"\n"</span></span><span>;
</span></span>
実際の使用では、双方向通信の基本的なプロセスを次の手順にまとめることができます。
接続の確立:クライアントはsocket_connectを介してサーバーに接続し、サーバーはクライアントがsocket_acceptを介して接続するのを待ちます。
メッセージの送信:クライアントまたはサーバーは、 socket_sendmsgを介してメッセージを送信できます。特定の制御情報を表すために、追加のデータまたはフラグビットを渡すことができることに注意する必要があります。
受信メッセージ:レシーバーはsocket_recvmsgを介してメッセージを受信します。受信したメッセージには、データパーツだけでなく、一部のメタデータ(メッセージフラグ、送信者など)も含まれます。
代替送信と受信:クライアントとサーバーは、双方向データ交換にsocket_sendmsgとsocket_recvmsgを交互に使用します。異なる制御情報またはより複雑なデータ構造を添付するたびに。
<span><span><span class="hljs-comment">// サーバー側のコードの例(簡素化されたバージョン)</span></span><span>
</span><span><span class="hljs-variable">$serverSocket</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_create</span></span><span>(AF_INET, SOCK_STREAM, SOL_TCP);
</span><span><span class="hljs-title function_ invoke__">socket_bind</span></span><span>(</span><span><span class="hljs-variable">$serverSocket</span></span><span>, </span><span><span class="hljs-string">'127.0.0.1'</span></span><span>, </span><span><span class="hljs-number">8080</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">socket_listen</span></span><span>(</span><span><span class="hljs-variable">$serverSocket</span></span><span>);
</span><span><span class="hljs-comment">// クライアント接続を待っています</span></span><span>
</span><span><span class="hljs-variable">$clientSocket</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_accept</span></span><span>(</span><span><span class="hljs-variable">$serverSocket</span></span><span>);
</span><span><span class="hljs-comment">// データを受信して送信します</span></span><span>
</span><span><span class="hljs-variable">$buffer</span></span><span> = </span><span><span class="hljs-string">''</span></span><span>;
</span><span><span class="hljs-variable">$header</span></span><span> = </span><span><span class="hljs-keyword">array</span></span><span>(
</span><span><span class="hljs-string">'msg_name'</span></span><span> => </span><span><span class="hljs-literal">null</span></span><span>,
</span><span><span class="hljs-string">'msg_namelen'</span></span><span> => </span><span><span class="hljs-number">0</span></span><span>,
</span><span><span class="hljs-string">'msg_iov'</span></span><span> => </span><span><span class="hljs-keyword">array</span></span><span>(</span><span><span class="hljs-keyword">array</span></span><span>(</span><span><span class="hljs-string">'iov_base'</span></span><span> => &</span><span><span class="hljs-variable">$buffer</span></span><span>, </span><span><span class="hljs-string">'iov_len'</span></span><span> => </span><span><span class="hljs-number">1024</span></span><span>)),
</span><span><span class="hljs-string">'msg_iovlen'</span></span><span> => </span><span><span class="hljs-number">1</span></span><span>,
</span><span><span class="hljs-string">'msg_control'</span></span><span> => </span><span><span class="hljs-literal">null</span></span><span>,
</span><span><span class="hljs-string">'msg_controllen'</span></span><span> => </span><span><span class="hljs-number">0</span></span><span>,
</span><span><span class="hljs-string">'msg_flags'</span></span><span> => </span><span><span class="hljs-number">0</span></span><span>
);
</span><span><span class="hljs-keyword">while</span></span><span> (</span><span><span class="hljs-literal">true</span></span><span>) {
</span><span><span class="hljs-variable">$bytesReceived</span></span><span> = </span><span><span class="hljs-title function_ invoke__">socket_recvmsg</span></span><span>(</span><span><span class="hljs-variable">$clientSocket</span></span><span>, </span><span><span class="hljs-variable">$header</span></span><span>);
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-variable">$bytesReceived</span></span><span> === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">break</span></span><span>;
}
</span><span><span class="hljs-keyword">echo</span></span><span> </span><span><span class="hljs-string">"クライアントからメッセージを受け取りました: <span class="hljs-subst">$buffer</span></span></span><span>\n";
</span><span><span class="hljs-comment">// クライアントに応答を送信します</span></span><span>
</span><span><span class="hljs-variable">$msg</span></span><span> = </span><span><span class="hljs-string">"Hello from server!"</span></span><span>;
</span><span><span class="hljs-variable">$msgHdrSend</span></span><span> = </span><span><span class="hljs-keyword">array</span></span><span>(
</span><span><span class="hljs-string">'msg_name'</span></span><span> => </span><span><span class="hljs-literal">null</span></span><span>,
</span><span><span class="hljs-string">'msg_namelen'</span></span><span> => </span><span><span class="hljs-number">0</span></span><span>,
</span><span><span class="hljs-string">'msg_iov'</span></span><span> => </span><span><span class="hljs-keyword">array</span></span><span>(</span><span><span class="hljs-keyword">array</span></span><span>(</span><span><span class="hljs-string">'iov_base'</span></span><span> => </span><span><span class="hljs-variable">$msg</span></span><span>, </span><span><span class="hljs-string">'iov_len'</span></span><span> => </span><span><span class="hljs-title function_ invoke__">strlen</span></span><span>(</span><span><span class="hljs-variable">$msg</span></span><span>))),
</span><span><span class="hljs-string">'msg_iovlen'</span></span><span> => </span><span><span class="hljs-number">1</span></span><span>,
</span><span><span class="hljs-string">'msg_control'</span></span><span> => </span><span><span class="hljs-literal">null</span></span><span>,
</span><span><span class="hljs-string">'msg_controllen'</span></span><span> => </span><span><span class="hljs-number">0</span></span><span>,
</span><span><span class="hljs-string">'msg_flags'</span></span><span> => </span><span><span class="hljs-number">0</span></span><span>
);
</span><span><span class="hljs-title function_ invoke__">socket_sendmsg</span></span><span>(</span><span><span class="hljs-variable">$clientSocket</span></span><span>, </span><span><span class="hljs-variable">$msgHdrSend</span></span><span>);
}
</span></span>
socket_sendmsgとsocket_recvmsg関数を使用すると、特に複雑なメッセージが必要なシナリオまたは追加の制御情報が渡されるシナリオでは、ソケットベースの通信効率を大幅に改善できます。それらの柔軟性により、開発者は双方向のコミュニケーションをよりよく実現し、メッセージを投票および制御することでデータ交換を完了できます。これらの機能がどのように使用されるかを理解することは、効率的なネットワーク通信を達成するために重要です。