分享
 
 
 

PHP套接字编程

王朝php·作者佚名  2006-12-16
窄屏简体版  字體: |||超大  

套接字编程,一般使用c或c++。特别的在web应用程序开发中,常用perl实现套接字。除此以外,用php进行套接字编程也是一个选择。Php可以胜任吗?当然可以。Php是一门高质量的web应用程序开发语言,他的许多特性可以处理众多的任务,网络编程也不例外。

1. 理解套接字

Mail、ftp、telnet、name和finger这些服务都是在一个专用的公开的端口上提供的,通过连接到这些端口,客户程序就能够访问这些服务。这与现实生活是相似的——当需要干洗衣服的时候,找干洗店;当需要取钱的时候,去银行,等等。除了专用于特定服务器的端口外,计算机还有其它的端口让程序员创建他们自己的服务器。

端口一般是编号的,通过指定服务器的端口号,客户程序可以连接到该端口上。每种服务器或端口要有特定的协议,为了让客户的请求能够被理解和响应,客户必须以这种服务器特有的方式形成客户请求。

Socket是网络上运行的两个程序间双向通信连接的一端。Socket这个词的一般意义是自然的或人工的插口,如家用电器的电源插口等。

客户程序可以向Socket写请求,服务器将处理此请求,然后通过Socket把结果返回给客户。

Socket是一种底层连接。客户机和服务器通过写入到Socket的字节流进行通信。它们必须有共同的协议,也就是说,通过Socket相互传送信息时所用的语言必须是协定好的。

2. Socket建立连接的过程

建立过程如下:(connection-oriented)

server 方过程 client 方过程

socket() socket()

| |

bind() bind()

| |

listen() |

| |

accept()<------------------connect()

| |

recv()/send() <----------> send()/recv()

3. Php 基本套接字调用:

3.1. 基本套接字调用

创建套接字--socket();

绑定本机端口--bind();

建立连接--connect(),accept();

侦听端口--listen();

数据传输--send(),recv();

输入/输出多路复用--select();

关闭套接字--closesocket()

3.2. php提供的套接字调用:

接受连接-—accept connect()

绑定端口—bind ()

关闭套接字—close()

初始化连接—connect()

侦听端口—listen()

读取套接字—read()

创建套接字—socket()

写套接字—write()

4. 基本应用

4.1. 一个简单的TCP服务器

1 #!/usr/local/bin/php -q

2

3 <?php

4 /*

5 * We don't want any time-limit for how the long can hang

6 * around, waiting for connections:

7 */

8 set_time_limit(0);

9

10 /* Create a new socket: */

11 if( ($sock = socket( AF_INET, SOCK_STREAM, 0 )) < 0 )

12 {

13 print strerror( $sock ) . "n";

14 exit(1);

15 }

16

17 /* Bind the socket to an address and a port: */

18 if( ($ret = bind( $sock, "10.31.172.77", 10000 )) < 0 )

19 {

20 print strerror( $ret ) . "n";

21 exit(1);

22 }

23

24 /*

25 * Listen for incoming connections on $sock.

26 * The '5' means that we allow 5 queued connections.

27 */

28 if( ($ret = listen( $sock, 5 )) < 0 )

29 {

30 print strerror( $ret ) . "n";

31 }

32

33 /* Accept incoming connections: */

34 if( ($msgsock = accept_connect( $sock )) < 0)

35 {

36 print strerror( $msgsock ) . "n";

37 exit(1);

38 }

39

40 /* Send the welcome-message: */

41 $message = "Welcome to my TCP-server!n";

42 if( ($ret = write( $msgsock, $message, strlen($message)) ) < 0 )

43 {

44 print strerror( $msgsock ) . "n";

45 exit(1);

46 }

47

48 /* Read/Receive some data from the client: */

49 $buf = '';

50 if( ($ret = read( $msgsock, $buf, 128 )) < 0 )

51 {

52 print strerror( $ret ) . "n";

53 exit(1);

54 }

55

56 /* Echo the received data back to the client: */

57 if( ($ret = write( $msgsock, "You said: $bufn", strlen("You said: $bufn")) ) < 0 )

58 {

59 print strerror( $ret ) . "n";

60 exit(1);

61 }

62

63 /* Close the communication-socket: */

64 close( $msgsock );

65

66 /* Close the global socket: */

67 close( $sock );

68 ?>

第8行:使用set_time_limit设定程序执行时间为无限以等待连接;

11-15: 创建一个套接字;

18-22: 把创建的套接字与IP及端口绑定;

28-31: 侦听端口;

34-38: 接受连接;

41-46: 显示欢迎信息;

49-54: 读取客户端信息;

57-61: 向客户端回显信息;

63-67: 关闭套接字

4.2. TCP服务器的运行

上边这个tcp服务器的运行要求php编译成cgi解释方式,并且编译时加入--enable-sockets。

||||||如果你已经编译成cgi解释方式运行,但是使用命令php -m列出的项目没有sockets,则说明你需要重新编译php。当这些要求达到后你就可以运行这个服务器了

启动服务器:

./filename.php

然后就可以使用telnet登录了。

telnet 10.31.172.77 10000

你的终端上将显示:

Trying 10.31.172.77...

Connected to 10.31.172.77.

Escape character is '^]'.

Welcome to my TCP server!

然后输入一些东西,并回车:

Hello

You said: Hello

Connection closed by foreign host

你也可以修改一下这个程序,让它像phpmanual上的那个例子,只有当客户端输入“quit“的时候才关闭连接。

5. 其他应用

5.1. 聊天室应用

5.1.1. 常见的聊天室实现

一般的聊天室的实现常使用的方法是使用框架页面,然后对其中一个用于显示谈话内容的框架使用html的方式刷新,例如:

<meta http-equiv=“refresh” content=”3;http://www.jite.net”>

使用这种方式会导致浏览器端不断的向服务器端发出请求,当有大量的请求时就会使得服务器运行效率降低。这样的聊天室显然是有设计弊端的。

但是如果使用socket的方式实现聊天室,情况就不同了。

5.1.2. 使用socket实现聊天室

我们要讨论的聊天室非常简单,只是一个原理上的实现。

它是一个 client/server 结构的程序, 首先启动 server, 然后用户使用 client 进行连接. client/server 结构的优点是速度快, 缺点是当 server 进行更新时, client 也必需更新.

初始化 server, 使server 进入监听状态: (以下只是实现原理,并不涉及具体程序)

$socket = socket( AF_INET,SOCK_STREAM, 0);

// 首先建立一个 socket, 族为 AF_INET, 类型为 SOCK_STREAM.

// AF_INET = ARPA Internet protocols 即使用 TCP/IP 协议族

// SOCK_STREAM 类型提供了顺序的, 可靠的, 基于字节流的全双工连接.

// 由于该协议族中只有一个协议, 因此第三个参数为 0

bind ($sock, $address, $port)

// 再将这个 socket 与某个地址进行绑定.

listen( sockfd, MAX_CLIENT)

// 地址绑定之后, server 进入监听状态.

// MAX_CLIENT 是可以同时建立连接的 client 总数.

server 进入 listen 状态后, 等待 client 建立连接。

Client端要建立连接首先也需要初始化连接:

$socket= socket( AF_INET,SOCK_STREAM,0))

// 同样的, client 也先建立一个 socket, 其参数与 server 相同.

connect ($socket, $address, $service_port)

// client 使用 connect 建立一个连接.

当 client 建立新连接的请求被送到Server端时, server 使用 accept 来接受该连接:

accept_connect($sock)

// accept 返回一个新的文件描述符.

在 server 进入 listen 状态之后, 由于可能有多个用户请求连接,所以程序需要同时对这些用户进行操作,并在它们之间实现信息交换。这在实现上称为I/O多路复用技术。

I/O多路复用技术的方法就不是本文所要叙述的内容了,如有兴趣请参考相关书籍。

5.2. 一个基于web的新闻组浏览器

在php中可以使用fsockopen打开一个tcp socket连接

int fsockopen (string hostname, int port [, int errno [, string errstr [, double timeout]]])

有关此函数的使用请参考php手册。

访问新闻组服务,需要使用一个协议叫NNTP,即Network News Transfer Protocol。

这个协议有一个专用的RFC描述,它位于 http://www.w3.org/Protocols/rfc977/rfc977.html。

该文档详细的说明了如何同一个nntp服务器对话及如何使用命令完成任务。

5.2.1. 连接一个服务器

<?php

$cfgServer = "news.php.net";

$cfgPort = 119;

$cfgTimeOut = 10;

// open a socket

if(!$cfgTimeOut)

// without timeout

$usenet_handle = fsockopen($cfgServer, $cfgPort);

else

// with timeout

$usenet_handle = fsockopen($cfgServer, $cfgPort, &$errno, &$errstr, $cfgTimeOut);

if(!$usenet_handle) {

echo "Connexion failedn";

exit();

}

else {

echo "Connectedn";

$tmp = fgets($usenet_handle, 1024);

}

?>

5.2.2. 同服务器进行对话

在前面,我们已经同服务器连接上了,假如我们要从某一新闻组中选取10条最近的新闻,该怎么办呢?

RFC977指出,选择一个新闻组使用group命令:

GROUP ggg

<?php

//$cfgUser = "xxxxxx";

//$cfgPasswd = "yyyyyy";

$cfgNewsGroup = "alt.php";

// identification required on private server

if($cfgUser) {

fputs($usenet_handle, "AUTHINFO USER ".$cfgUser."n");

$tmp = fgets($usenet_handle, 1024);

fputs($usenet_handle, "AUTHINFO PASS ".$cfgPasswd."n");

$tmp = fgets($usenet_handle, 1024);

// check error

if($tmp != "281 Okrn") {

echo "502 Authentication errorn";

exit();

}

}

// select newsgroup

fputs($usenet_handle, "GROUP ".$cfgNewsGroup."n");

$tmp = fgets($usenet_handle, 1024);

if($tmp == "480 Authentication required for commandrn") {

echo "$tmpn";

exit();

}

$info = split(" ", $tmp);

$first = $info[2];

$last = $info[3];

print "First : $firstn";

print "Last : $lastn";

?>

5.2.3. 读取新闻

读取新闻的命令是article,具体用法请参考RFC977,这里就不提供例程了。

6. 后记

我以为上次写了一篇,这次就可以免了。离交稿日期没几天了,于荣赋来约稿。程稿仓促,难免有错,请见谅,并且指出。

7. 参考文献:

廖斌,《php的守护程序编程》;

w3c,《RFC977》;

Daniel Solin,Introduction to Socket Programming with PHP;

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有