十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
1.参考资料
创新互联建站是一家专业提供渝水企业网站建设,专注与成都网站制作、成都网站设计、外贸营销网站建设、H5高端网站建设、小程序制作等业务。10年已为渝水众多企业、政府机构等服务。创新互联专业网站建设公司优惠进行中。
socket_create()函数需要三个参数:一个协议、一个socket类型、一个公共协议。socket_create()函数运行成功返回一个
包含socket的资源类型,如果没有成功则返回false。
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() 写数据到分散/聚合数组
2.代码:
?php
$sendStr = '30 32 30 34 03 30 33'; // 16进制数据
$sendStrArray = str_split(str_replace(' ', '', $sendStr), 2); // 将16进制数据转换成两个一组的数组
$socket = socket_create(AF_INET, SOCK_STREAM, getprotobyname("tcp")); // 创建Socket
if (socket_connect($socket, "192.168.1.100", 8080)) { //连接
for ($j = 0; $j count($sendStrArray); $j++) {
socket_write($socket, chr(hexdec($sendStrArray[$j]))); // 逐组数据发送
}
$receiveStr = "";
$receiveStr = socket_read($socket, 1024, PHP_BINARY_READ); // 采用2进制方式接收数据
$receiveStrHex = bin2hex($receiveStr); // 将2进制数据转换成16进制
echo "client:" . $receiveStrHex;
}
socket_close($socket); // 关闭Socket
?
?php
use Workerman\Worker;
require_once './Workerman/Autoloader.php';
// 初始化一个worker容器,监听1234端口
$worker = new Worker('websocket://0.0.0.0:1234');
// 这里进程数必须设置为1
$worker-count = 1;
// worker进程启动后建立一个内部通讯端口
$worker-onWorkerStart = function($worker)
{
// 开启一个内部端口,方便内部系统推送数据,Text协议格式 文本+换行符
$inner_text_worker = new Worker('Text://0.0.0.0:5678');
$inner_text_worker-onMessage = function($connection, $buffer)
{
global $worker;
// $data数组格式,里面有uid,表示向那个uid的页面推送数据
$data = json_decode($buffer, true);
$uid = $data['uid'];
// 通过workerman,向uid的页面推送数据
$ret = sendMessageByUid($uid, $buffer);
// 返回推送结果
$connection-send($ret ? 'ok' : 'fail');
};
$inner_text_worker-listen();
};
// 新增加一个属性,用来保存uid到connection的映射
$worker-uidConnections = array();
// 当有客户端发来消息时执行的回调函数
$worker-onMessage = function($connection, $data)use($worker)
{
// 判断当前客户端是否已经验证,既是否设置了uid
if(!isset($connection-uid))
{
// 没验证的话把第一个包当做uid(这里为了方便演示,没做真正的验证)
$connection-uid = $data;
/* 保存uid到connection的映射,这样可以方便的通过uid查找connection,
* 实现针对特定uid推送数据
*/
$worker-uidConnections[$connection-uid] = $connection;
return;
}
};
// 当有客户端连接断开时
$worker-onClose = function($connection)use($worker)
{
global $worker;
if(isset($connection-uid))
{
// 连接断开时删除映射
unset($worker-uidConnections[$connection-uid]);
}
};
// 向所有验证的用户推送数据
function broadcast($message)
{
global $worker;
foreach($worker-uidConnections as $connection)
{
$connection-send($message);
}
}
// 针对uid推送数据
function sendMessageByUid($uid, $message)
{
global $worker;
if(isset($worker-uidConnections[$uid]))
{
$connection = $worker-uidConnections[$uid];
$connection-send($message);
return true;
}
return false;
}
// 运行所有的worker(其实当前只定义了一个)
Worker::runAll();
启动后端服务
php push.php start -d
前端接收推送的js代码
var ws = new WebSocket('ws://127.0.0.1:1234');
ws.onopen = function(){
var uid = 'uid1';
ws.send(uid);
};
ws.onmessage = function(e){
alert(e.data);
};
后端推送消息的代码
// 建立socket连接到内部推送端口
$client = stream_socket_client('tcp://127.0.0.1:5678', $errno, $errmsg, 1, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT);
// 推送的数据,包含uid字段,表示是给这个uid推送
$data = array('uid'='uid1', 'percent'='88%');
// 发送数据,注意5678端口是Text协议的端口,Text协议需要在数据末尾加上换行符
fwrite($client, json_encode($data)."\n");
// 读取推送结果
echo fread($client, 8192);
这里的uid不一定是用户的id,也可以理解为任务id即 taskid
以上代码亲测可以直接使用
接收指定IP的数据包,其他IP都要过滤吧,那就用防火墙来搞吧
使用的是client段的获取方式,用client的可以指定IP,代码大概如下
public void SendMessage()
{
ASCII = Encoding.ASCII;
// 构造用于发送的 字节缓冲.
Byte[] sendBytes = ASCII.GetBytes(SEND_MESSAGE);
// 构造用于接收的 字节缓冲.
Byte[] recvBytes = new Byte[256];
// IP地址.
IPAddress localAddr = IPAddress.Parse("192.168.19.81");
// 接入点.
IPEndPoint ephost = new IPEndPoint(localAddr, PORT);
// 第一个参数:AddressFamily = 指定 Socket 类的实例可以使用的寻址方案。
// Unspecified 未指定地址族。
// InterNetwork IP 版本 4 的地址。
// InterNetworkV6 IP 版本 6 的地址。
//
// 第二个参数:SocketType = 指定 Socket 类的实例表示的套接字类型。
// Stream 一个套接字类型,支持可靠、双向、基于连接的字节流,而不重复数据,也不保留边界。
// 此类型的 Socket 与单个对方主机通信,并且在通信开始之前需要建立远程主机连接。
// 此套接字类型使用传输控制协议 (Tcp),AddressFamily 可以是 InterNetwork,也可以是 InterNetworkV6。
//
// 第三个参数:ProtocolType = 指定 Socket 类支持的协议。
// Tcp 传输控制协议 (TCP)。
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
// 尝试连接主机.
s.Connect(ephost);
//Console.WriteLine("向服务器发送到了:{0}", SEND_MESSAGE);
// 向主机发送数据.
// s.Send(sendBytes, sendBytes.Length, SocketFlags.None);
// 接收服务器的应答.
Int32 bytes = s.Receive(recvBytes, recvBytes.Length, SocketFlags.None);
StringBuilder buff = new StringBuilder();
// while (bytes 0)
// {
// 将缓冲的字节数组,装换为字符串.
// String str = ASCII.GetString(recvBytes, 0, bytes);
String str = "";
for (int i = 0; i recvBytes.Length; i++)
{
str = str + recvBytes[i];
}
int iCount = 0;
iCount = int.Parse(str.Substring(13, 6)) ;
// 加入字符串缓存
buff.Append(str);
// 再次接受,看看后面还有没有数据.
//bytes = s.Receive(recvBytes, recvBytes.Length, SocketFlags.None);
// }
textBox1.Text = iCount.ToString();
}
catch (Exception ex)
{
MessageBox.Show("连接/发送/接收过程中,发生了错误!");
MessageBox.Show(ex.Message);
//Console.WriteLine("连接/发送/接收过程中,发生了错误!");
//Console.WriteLine(ex.Message);
//Console.WriteLine(ex.StackTrace);
}
finally
{
s.Close();
}