圣泉山人 后端开发工程师

Socket

2016-04-21
PHP

Soket是什么?

Soket又叫套接字,是一个通信链的句柄,应用程序通过它来向网络发出请求或者响应请求。其本质是是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。

工作位置如下:

img

工作原理如下:

img

过程详解:

服务器端先初始化Socket,然后与端口绑定,对端口进行监听,调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器,如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。

socket相关函数

  • socket_accept() 接受一个Socket连接
  • socket_bind() 把socket绑定在一个IP地址和端口上
  • socket_clear_error() 清除socket的错误或者最后的错误代码
  • socket_close() 关闭一个socket资源
  • socket_connect() 开始一个socket连接
  • socket_create_listen() 在指定端口打开一个socket监听
  • socket_create_pair() 产生一对没有区别的socket到一个数组里
  • socket_create() 产生一个socket,相当于产生一个socket的数据结构
  • socket_get_option() 获取socket选项
  • socket_getpeername() 获取远程类似主机的ip地址
  • socket_getsockname() 获取本地socket的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的最后错误代码
  • socket_listen() 监听由指定socket的所有连接
  • socket_read() 读取指定长度的数据
  • socket_readv() 读取从分散/聚合数组过来的数据
  • socket_recv() 从socket里结束数据到缓存
  • socket_recvfrom() 接受数据从指定的socket,如果没有指定则默认当前socket
  • socket_recvmsg() 从iovec里接受消息
  • socket_select() 多路选择
  • socket_send() 这个函数发送数据到已连接的socket
  • socket_sendmsg() 发送消息到socket
  • socket_sendto() 发送消息到指定地址的socket
  • socket_set_block() 在socket里设置为块模式
  • socket_set_nonblock() socket里设置为非块模式
  • socket_set_option() 设置socket选项
  • socket_shutdown() 这个函数允许你关闭读、写、或者指定的socket
  • socket_strerror() 返回指定错误号的详细错误
  • socket_write() 写数据到socket缓存
  • socket_writev() 写数据到分散/聚合数组

使用示例

服务端

/**
 * socket服务端全过程
 */

if (!extension_loaded('sockets')) {
	die('socket扩展还未加载!');
}

//防止超时
set_time_limit(0);

$ip = '127.0.0.1';
$port = 1935;

//1、创建套接字
if (($sock = socket_create(AF_INET , SOCK_STREAM , SOL_TCP )) ===  false) {
	echo  "创建socket失败,原因是:"  .  socket_strerror(socket_last_error()) .  "\n" ;
}

//2、绑定address到socket
if (socket_bind($sock, $ip, $port) === false) {
	echo  "socket绑定地址失败,原因是:"  .  socket_strerror(socket_last_error()) .  "\n" ;
}

//3、告知socket开始监听,第二个参数指定队列中最多可容纳的等待接受的传入连接数
if (socket_listen($sock, 5) === false) {
	echo  "socket监听失败,原因是:"  .  socket_strerror(socket_last_error()) .  "\n" ;
}

do {
	//4、接收连接请求并调用另一个socket处理客户端和服务器间的信息
	if (($msgsock = socket_accept($sock)) === false) {
		echo "accept失败,原因是: " . socket_strerror(socket_last_error($sock)) . "\n";
		break;
	}

	//5、把缓冲区内容写入socket
	$msg = "服务端:测试成功!\n";
	socket_write($msgsock, $msg, strlen($msg));


	//6、从socket中读取数据
	if (($buf = socket_read($msgsock, 2048, PHP_NORMAL_READ)) === false) {
		echo "从socket中读取数据失败,原因是: " . socket_strerror(socket_last_error($msgsock)) . "\n";
		break;
	}

	$talkback = "客户端发的消息是:" . $buf . "\n";
	socket_write($msgsock, $talkback, strlen($talkback));
	echo " $buf \n";

} while (true);

//关闭socket
socket_close ($sock);

客户端:

/**
 * socket客户端全过程
 */

if (!extension_loaded('sockets')) {
	die('socket扩展还未加载!');
}

error_reporting(E_ALL);
set_time_limit(0);

echo "TCP/IP Connection\n";

$service_port = 1935;
$ip = "127.0.0.1";

//1、创建socket
$socket  =  socket_create ( AF_INET ,  SOCK_STREAM ,  SOL_TCP );
if ( $socket  ===  false ) {
	echo  "socket_create() 失败,原因是:"  .  socket_strerror ( socket_last_error ()) .  "\n" ;
} else {
	echo  "OK.\n" ;
}

echo  "尝试连接到:' $ip ' ,端口: ' $service_port '..." ;

//2、连接socket
$result  =  socket_connect ( $socket ,  $ip ,  $service_port );
if ( $result  ===  false ) {
	echo  "socket_connect()失败.\n原因是: ( $result ) "  .  socket_strerror ( socket_last_error ( $socket )) .  "\n" ;
} else {
	echo  "OK.\n" ;
}

$in  =  "HEAD / HTTP/1.1\r\n" ;
$in  .=  "Host: www.test.com\r\n" ;
$in  .=  "Connection: Close\r\n\r\n" ;
$out  =  '' ;

echo  "Sending HTTP HEAD request..." ;

//3、发送数据
socket_write($socket, $in, strlen($in));
echo  "OK.\n" ;

echo  "Reading response:\n\n" ;

//4、读取返回数据
while ($out = socket_read($socket, 2048)) {
	echo $out;
}

echo  "Closing socket..." ;

//5、关闭socket
socket_close($socket);
echo  "OK.\n\n" ;

然后在cmd上先用php执行服务端代码,确保soket创建成功,并处于等待连接状态(运行后可使用netstat -ano命令查看指定端口是否处于监听状态),然后再运行客户端代码查看是否连接正常。

注意

由于php语言本身的特性决定了其只适合做soket的客户端(比如连接Mysql就是通过soket进行的),而不适合做服务端,因为soket只要面向底层和网络服务开发,而用c语言、java等来实现的话能更好的操作底层,并且在网络服务开发中遇到的问题也有更完善、成熟的解决方案。

原文:http://www.cnblogs.com/thinksasa/archive/2013/02/26/2934206.html


上一篇 Sphinx

下一篇 Vagrant

Comments

Content