在以前的項目中,就曾聽說過swoole的大名,想用來進行消息推送,但是當時隻是有了初步的了解,并不敢大膽的運用到線上産品。所謂 識不足則多慮,威不足則多怒。
最近閑來無事,又重新溫習了一下swoole的消息通知功能,雖然在項目開發當時,也曾實作過簡單的操作的,但是這次溫習更加深了學習,配合vb.net進行開發,感覺還是棒棒哒,下面是一套實作過程,如有需要參考,請拿去...
在以前的項目中,就曾聽說過swoole的大名,想用來進行消息推送,但是當時隻是有了初步的了解,并不敢大膽的運用到線上産品。所謂 識不足則多慮,威不足則多怒、是以就是怕,隻能跟上司說了運用極光的推送功能,而且還說出了一定的理由,上司自然也隻有相信了,那就用極光推送吧!
最近閑來無事,又重新溫習了一下swoole的消息通知功能,雖然在項目開發當時,也曾實作過簡單的操作的,但是這次溫習更加深了學習,配合vb.net進行開發,感覺還是棒棒哒,下面是一套實作過程,如有需要參考,請拿去,不謝!
首先,我的開發平台是windows,雖然本人也裝有virtual box虛拟機,但是那玩意兒太耗記憶體cpu了,開起來搞實在不想搞。是以,就用了cygwin進行配置開發環境搭建,這裡我就不說具體安裝步驟了,給個連結吧,一步步按着操作就行了。 檢視php在window下安裝swoole擴充的方法 請點選。 ps: 如果你win系統裡已經安裝了一套wamp環境,在cygwin中使用php或其他和win有相同名稱指令時,請記得使用全路徑 如:/bin/php index.php , /bin/find / -name "init*"
第二步、編寫php服務端程式,命名 test_tcp_server.php , 代碼如下:
<?php
$serv = new swoole_server("127.0.0.1", 9501);
$serv->set(array(
'worker_num' => 2, //工作程序數量
// 'daemonize' => true, //是否作為守護程序,玩玩就不要開啟這東西了,不然你都不知道跑到哪裡去了
));
$serv->on('connect', 'my_onConnect');
$serv->on('receive', 'my_onReceive');
$serv->on('close', 'my_onClose');
echo "swoole_server is running on 127.0.0.1 9501 \n";
$serv->start();
//receive msg respond
function my_onReceive ($serv, $fd, $from_id, $data) {
// var_dump($serv);
$data = trim($data);
// 發送給誰, 如:@id msg... , 最好的當然是使用redis或者資料庫存入号碼并生成一個映射了,不過玩玩就不要認真了
if(substr($data, 0, 1) == '@'){
$splitStart = strpos($data, ' ');
$toUserId = substr($data, 1, $splitStart - 1);
echo 'Send to:' . $toUserId . ';';
$content = substr($data, $splitStart + 1);
if(is_numeric($toUserId)){
$serv->send($toUserId, "From Client[$fd@$from_id]:" . $content);
}elseif(strtolower($toUserId) == 'all'){
broadcast($serv, $fd, $content);
}else{
$serv->send($fd, 'Swoole: Unkown to user ' . strtolower($toUserId) . ' infomation.');
}
}else{
echo "From Client[$fd@$from_id],received data: " . $data . PHP_EOL;
$serv->send($fd, 'Swoole: '.$data);
}
// $serv->close($fd);
}
//connect action
function my_onConnect ($serv, $fd){
echo "Client:Connect. id:{$fd}\n";
}
//close action
function my_onClose ($serv, $fd) {
echo "Client: Close. id:{$fd}\n";
}
//broadcast except me, 隻會廣播from_id相同的使用者,再研究了
function broadcast(swoole_server $serv, $fd = 0, $data = "hello")
{
$start_fd = 0;
$sendNum = 0;
echo "broadcast to ";
$from = "From Client[$fd]:";
while(true)
{
$conn_list = $serv->connection_list($start_fd, 10);
if($conn_list === false)
{
break;
}
var_dump($conn_list);
$start_fd = end($conn_list);
foreach($conn_list as $conn)
{
if($conn === $fd) continue;
$ret1 = $serv->send($conn, $from . $data);
$sendNum ++;
}
}
echo $sendNum . ' numbers.';
}
記得把它跑起來哦
/bin/php test_tcp_server.php
第三步,你可以編寫一個用戶端程式,也可以不用編寫,因為其他工具也完全可以連接配接進行的呢!如果要定,可以參考swoole官網的tcp_client代碼,如下:
<?php
$client = new swoole_client(SWOOLE_SOCK_TCP, SWOOLE_SOCK_ASYNC);
//設定事件回調函數
$client->on("connect", function($cli) {
$cli->send("hello world\n");
});
$client->on("receive", function($cli, $data){
echo "Received: ".$data."\n";
});
$client->on("error", function($cli){
echo "Connect failed\n";
});
$client->on("close", function($cli){
echo "Connection close\n";
});
//發起網絡連接配接
$client->connect('127.0.0.1', 9501, 0.5);
正常的話,運作這個腳本,你就可以收到消息了如: 'From Client[1@0],received data: hello,world'
第四步、你肯定不滿足于使用php語言去連接配接伺服器端,你當然不應該滿足!你還可以使用windows的cmd指令行嘛,如下:
telnet 127.0.0.1 9501

然後,你會發現,怎麼隻輸入了一個字元就發送了。原因是什麼win的telnet協定之類的,使用send指令,就可以了。操作為:按鍵 ctrl + ] ,進入telnet 指令行模式,輸入send aaaddd
ok,多開幾個用戶端,看起來會話就可以了呢(要檢視傳回的内容,直接按Enter鍵即可,切換回來使用ctrl + ]),來看看服務端都什麼樣子吧:
都是有響應的吧,ok了,現在再試試一個功能, send @10 hello,10, you ok ? ,則另一個用戶端就收到消息了
ok,到此為止,基本上測試完成了。但是使用cmd畢竟看起來不爽,于是想到用vb.net去實作一個用戶端。代碼就簡要的貼出來,看看吧。
第五步,使用vb.net實作用戶端通路:
Imports System
Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Public Class SynchronousSocketClient
Protected Shared port As Integer = 9501
Protected Shared host As String = "localhost"
Private Shared sender As Socket
Public Shared bytes(1024) As Byte
' A way to the connect to the server
Public Shared Sub Main()
If (IsNothing(sender)) OrElse Not sender.Connected Then
If Not IsNothing(Form1.TextBox1.Text) Then
host = Form1.TextBox1.Text
End If
If (Form1.TextBox2.Text) Then
port = Form1.TextBox2.Text
End If
sender = ConnectSocket(host, port)
End If
End Sub
' send something to server
Public Shared Sub send()
If (IsNothing(sender)) OrElse Not sender.Connected Then
If Not IsNothing(Form1.TextBox1.Text) Then
host = Form1.TextBox1.Text
End If
If (Form1.TextBox2.Text) Then
port = Form1.TextBox2.Text
End If
sender = ConnectSocket(host, port)
End If
' Encode the data string into a byte array.
Dim msg As Byte() = Encoding.ASCII.GetBytes(Form1.myContent.Text)
' Send the data through the socket.
Dim bytesSent As Integer = sender.Send(msg)
' Receive the response from the remote device.
Dim bytesRec As Integer = sender.Receive(bytes)
Console.WriteLine("ServerReturn = {0}", Encoding.ASCII.GetString(bytes, 0, bytesRec))
Form1.infoText.Text &= "ServerReturn = " & Encoding.ASCII.GetString(bytes, 0, bytesRec) & vbNewLine
End Sub
' connect initialize
Private Shared Function ConnectSocket(ByVal host As String, ByVal port As Integer) As Socket '建立連接配接
Dim s As Socket = Nothing
Dim hostEntry As IPHostEntry = Nothing
'address = System.Net.IPAddress.Parse(host)
Dim ipHostInfo As IPHostEntry = Dns.Resolve(host)
Dim address As IPAddress = ipHostInfo.AddressList(0)
Dim endPoint As New IPEndPoint(address, port)
Dim tempSocket As New Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)
tempSocket.Connect(endPoint)
If tempSocket.Connected Then
s = tempSocket
Console.WriteLine("Socket connected to {0}", tempSocket.RemoteEndPoint.ToString())
Form1.infoText.Text &= "Socket connected to " & tempSocket.RemoteEndPoint.ToString()
End If
Return s
End Function
' close socket
Public Shared Sub closeSocket()
If (sender.Connected) Then
Form1.infoText.Text &= "Socket closed : " & sender.RemoteEndPoint.ToString() & vbNewLine
sender.Shutdown(SocketShutdown.Both)
sender.Close()
End If
End Sub
End Class 'SynchronousSocketClient
如上是通路連接配接伺服器的代碼,觸發代碼則是在另一個頁面進行的,界面如下:
運作後效果如下:
觸發事件的代碼就比較簡單了,還是貼一下吧:
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
'Console.WriteLine("console ", Rnd) ' 無法讀取最後一行console其實
SynchronousSocketClient.Main()
'AsynchronousClient.Main() ' 異步功能并未實作呢
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
infoText.Text = ""
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
SynchronousSocketClient.send()
End Sub
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
SynchronousSocketClient.closeSocket()
End Sub
End Class
到此,打完,收工。由于異步的調試沒有成功,就此打住吧,以後有興趣再去搞了!
不要害怕今日的苦,你要相信明天,更苦!