PHP Socket 编程过程详解

澳门新葡亰赌995577 4

介绍

Socket用于进程间通信。进程间通信通常基于客户端—服务端模型。此时,客户端—服务端是可以彼此交互的应用程序。客户端和服务端之间的交互需要连接。Socket编程负责的就是为应用程序之间建立可进行交互的连接。

在本文中,我们将学习如何用PHP创建一个简单的客户端—服务端。我们还将学习如何客户端应用程序如何发送消息到服务端,以及如何从服务端接受消息。

澳门新葡亰赌995577 1

1.2 Socket 类

Socket (套接字) 是网络连接的端点。Socket
使应用程序可以从网络中读取数据,可以向网络中写入数据。不同计算机上的两个应用程序可以通过连接发送或接收字节流,以此达到相互通信的目的。为了从一个应用程序向另一个应用程序发送消息,需要知道另一个应用程序中
Socket 的 IP 地址和端口号。

public class Socket
extends Object
implements Closeable
This class implements client sockets (also called just “sockets”). A
socket is an endpoint for communication between two machines.
The actual work of the socket is performed by an instance of the
SocketImpl class. An application, by changing the socket factory
that creates the socket implementation, can configure itself to create
sockets appropriate to the local firewall.

创建一个 Socket :

Socket() Creates an unconnected socket, with the system-default type of SocketImpl.
Socket(String host, int port) Creates a stream socket and connects it to the specified port number on the named host.
Socket(String host, int port, boolean stream) Deprecated. Use DatagramSocket instead for UDP transport.

host – the host name, or null for the loopback address.

port – the port number.

host:远程主机的名称或 IP 地址 (127.0.0.1 表示一个本地主机)
post:连接远程应用程序的端口号

使用 socket 实例发送/接收字节流:
socket.getOutputStream()

发送文本
PrintWriter out = new PrintWriter(socket.getOutputStream(), true)

接收字节流:
socket.getInputStream()

本文由码农网 –
小峰原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划!

Result

GET /source.html HTTP/1.1
Host: localhost:8080
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Upgrade-Insecure-Requests: 1
Cookie: __utma=111872281.722673633.1521287843.1521287843.1521287843.1; __utmz=111872281.1521287843.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); Idea-7e6930cd=8b83b26b-bd8b-480c-832b-3c0b6e5d4c39
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0.3 Safari/604.5.6
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
Connection: keep-alive

GET /favicon.ico HTTP/1.1
Host: localhost:8080
Accept: */*
Connection: keep-alive
Cookie: __utma=111872281.722673633.1521287843.1521287843.1521287843.1; __utmz=111872281.1521287843.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); Idea-7e6930cd=8b83b26b-bd8b-480c-832b-3c0b6e5d4c39
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0.3 Safari/604.5.6
Accept-Language: zh-cn
Referer: http://localhost:8080/source.html
Accept-Encoding: gzip, deflate

澳门新葡亰赌995577 2

ch1_result.png

许可证

这篇文章,以及任何相关的源代码和文件,是经过The Code Project Open
License (CPOL)许可的。

1.1 HTTP

HTTP
RFC 2616 – Hypertext Transfer Protocol —
HTTP/1.1
版本: HTTP/1.1
TCP 连接
基于:“请求—响应”的协议

澳门新葡亰赌995577,使用代码

目的:开发一个客户端用于发送string消息到服务端,服务端将相同的信息反转后返回给客户端。

PHP服务器

第1步:设置变量,如“主机”和“端口”

$host = "127.0.0.1";
$port = 5353;
// No Timeout 
set_time_limit(0);

端口号可以是1024 -65535之间的任何正整数。

第2步:创建socket

$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socketn");

第3步:绑定socket到端口和主机

创建的socket资源绑定到IP地址和端口号。

$result = socket_bind($socket, $host, $port) or die("Could not bind to socketn");

第4步:启动socket监听

在绑定到IP和端口后,服务端开始等待客户端的连接。在没有连接之前它就一直等下去。

$result = socket_listen($socket, 3) or die("Could not set up socket listenern");

第5步:接受连接

这个函数会接受所建的socket传入的连接请求。在接受来自客户端socket的连接后,该函数返回另一个socket资源,实际上就是负责与相应的客户端socket通信。这里的“$spawn”就是负责与客户端socket通信的socket资源。

$spawn = socket_accept($socket) or die("Could not accept incoming connectionn");

到现在为止,我们已经准备好了服务端socket ,但实际上这个脚本并没有做任何事情。所以为了继续完成上述目标,我们将读取客户端socket消息,然后将接收到的消息反转后发回给客户端socket。

第6步:从客户端socket读取消息

$input = socket_read($spawn, 1024) or die("Could not read inputn");

第7步:反转消息

$output = strrev($input) . "n";

第8步:发送消息给客户端socket

socket_write($spawn, $output, strlen ($output)) or die("Could not write outputn");

关闭socket

socket_close($spawn);
socket_close($socket);

这就完成了服务端。现在,我们学习如何创建PHP客户端。

PHP客户端

前两个步骤与服务端相同。

第1步:设置变量,如“主机”和“端口”

$host = "127.0.0.1";
$port = 5353;
// No Timeout 
set_time_limit(0);

注:这里的端口和主机应该和服务端中的定义是相同的。

第2步:创建socket

$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socketn");

第3步:连接到服务端

$result = socket_connect($socket, $host, $port) or die("Could not connect toservern");

此时和服务端不同,客户端socket不绑定端口和主机。相反,它连接到服务端socket,等待接受来自客户端socket的连接。这一步建立了客户端socket到服务端socket的连接。

第4步:写入服务端socket

socket_write($socket, $message, strlen($message)) or die("Could not send data to servern");

在此步骤中,客户端socket的数据被发送到服务端socket。

第5步:阅读来自服务端的响应

$result = socket_read ($socket, 1024) or die("Could not read server responsen");
echo "Reply From Server  :".$result;

第6步:关闭socket

socket_close($socket);

完整的代码

服务端(server.php)

// set some variables
$host = "127.0.0.1";
$port = 25003;
// don't timeout!
set_time_limit(0);
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socketn");
// bind socket to port
$result = socket_bind($socket, $host, $port) or die("Could not bind to socketn");
// start listening for connections
$result = socket_listen($socket, 3) or die("Could not set up socket listenern");

// accept incoming connections
// spawn another socket to handle communication
$spawn = socket_accept($socket) or die("Could not accept incoming connectionn");
// read client input
$input = socket_read($spawn, 1024) or die("Could not read inputn");
// clean up input string
$input = trim($input);
echo "Client Message : ".$input;
// reverse client input and send back
$output = strrev($input) . "n";
socket_write($spawn, $output, strlen ($output)) or die("Could not write outputn");
// close sockets
socket_close($spawn);
socket_close($socket);

客户端(client.php)

$host    = "127.0.0.1";
$port    = 25003;
$message = "Hello Server";
echo "Message To server :".$message;
// create socket
$socket = socket_create(AF_INET, SOCK_STREAM, 0) or die("Could not create socketn");
// connect to server
$result = socket_connect($socket, $host, $port) or die("Could not connect to servern");  
// send string to server
socket_write($socket, $message, strlen($message)) or die("Could not send data to servern");
// get server response
$result = socket_read ($socket, 1024) or die("Could not read server responsen");
echo "Reply From Server  :".$result;
// close socket
socket_close($socket);

建立上述文件(server.php和client.php)后,执行如下操作:

  1. 复制www目录中的这些文件(假设WAMP),安置于C:wamp。
  2. 打开Web浏览器,在地址栏中键入localhost 。
  3. 先浏览server.php然后client.php。

1.1.1 HTTP 请求

一个 HTTP 请求包含以下三部分
* 请求方法 —— URI(Uniform Resource Identifier, 统一资源标识符)
* 请求头
* 实体

POST /examples/default.jsp HTTP/1.1
Accept: text/plain; text/html
Accept-Language: en-gb
Connection: Keep-Alive
Host: Localhost
User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)
Content-Length: 33
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip, deflate

lastName=Franks&firstName=Michael

澳门新葡亰赌995577 3

http .png

HTTP 支持的七种请求方法

  1. GET
  2. POST
  3. HEAD
  4. OPTIONS
  5. PUT
  6. DELET
  7. TRACE

URI(Uniform Resource Identifier, 统一资源标识符) 制定 Internet
资源的完整路径。 URI
通常会被解释为相对于服务器根目录的相对路径,因此,它总是以 “/”
开头的。
URL(Uniform Resource Locator, 统一资源定位符) 实际上是 URI 的一种类型。

版本协议指明了当前请求使用的 HTTP 协议的版本。

1.3 应用程序

本章的 Web 服务器包括三个类:

  • HttpServer
  • Request
  • Response
  1. 程序的入口点(静态 main()方法)在 HttpServer
    类中。main()方法创建一个 HttpServer 实例,然后调用其 await()
    方法。
  2. await()方法会在指定端口上等待 HTTP
    请求,对其处理,然后发送响应信息回客户端。在接收到关闭命令前,它会保持等待状态。

该应用程序仅发送位于指定目录的静态资源请求,如 HTML
文件和图像文件,它将传入到的 HTTP
请求字节流现实到控制台上。但是它不发送任何 header (头信息)
到浏览器,如日期或 cookies 等。

1.1.2 HTTP 响应

一个 HTTP 响应包括三部分

  • 协议——状态码——描述
  • 响应头
  • 相应实体段

HTTP/1.1 200 OK
Server: Microsoft-IIS/4.0
Data: Mon, 5 Jan 2004 13:13:33 GMT
Content-Length: 112

<html>
    <head>
        <title>HTTP Response Example</title>
    </head>
    <body>
        Welcome to Brainy Software
    </body>
</html>

澳门新葡亰赌995577 4

http-respond.jpg

状态码 200 表示请求成功。
响应实体正文是一段 HTML 代码

ServerSocket 类

Socket 类:表示一个客户端套接字。
ServerSocket 类:服务器套接字。

public class ServerSocket
extends Object
implements Closeable
This class implements server sockets. A server socket waits for
requests to come in over the network. It performs some operation based
on that request, and then possibly returns a result to the
requester.
The actual work of the server socket is performed by an instance of
the SocketImpl class. An application can change the socket factory
that creates the socket implementation to configure itself to create
sockets appropriate to the local firewall.

服务器套接字要等待来自客户端的连接请求。当服务器套接字接收到了连接请求之后,它会创建一个
Socket 实例来处理与客户端的通信。

ServerSocket 的构造函数

Constructor Description
ServerSocket() Creates an unbound server socket.
ServerSocket(int port) Creates a server socket, bound to the specified port.
ServerSocket(int port, int backlog) Creates a server socket and binds it to the specified local port number, with the specified backlog.
ServerSocket(int port, int backlog,InetAddress bindAddr) Create a server with the specified port, listen backlog, and local IP address to bind to.

port – the port number, or 0 to use a port number that is
automatically allocated.

backlog – requested maximum length of the queue of incoming
connections.

bindAddr – the local InetAddress the server will bind to

backlog:服务端socket处理客户端socket连接是需要一定时间的。ServerSocket有一个队列,存放还没有来得及处理的客户端Socket,这个队列的容量就是backlog的含义。如果队列已经被客户端socket占满了,如果还有新的连接过来,那么ServerSocket会拒绝新的连接。也就是说backlog提供了容量限制功能,避免太多的客户端socket占用太多服务器资源。

bindAddr:必须是 java.net.InetAddress. 类的实例

创建 InetAddress 实例对象的一种简单方法是调用其静态方法
getByName(),传入包含主机名的字符串:

InetAddress.getByName("127.0.0.1");

创建了 ServerSocket
实例后,可以使其等待传入的连接请求,该请求会通过服务器套接字侦听的端口上的绑定地址传入,这些工作可以通过调用
ServerSocket 类的 accept
方法完成。只有收到连接请求后,该方法才会返回。

public Socket accept() throws IOException

A new Socket s is created and, if there is a security manager, the
security manager’s checkAccept method is called with
s.getInetAddress().getHostAddress() and s.getPort() as its
arguments to ensure the operation is allowed. This could result in a
SecurityException.

Returns: the new Socket.

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章

网站地图xml地图