在之前的項目中,就曾據說過swoole的大名,想用來進行消息推送,可是當時只是有了初步的瞭解,並不敢大膽的運用到線上產品。所謂 識不足則多慮,威不足則多怒、因此就是怕,只能跟領導說了運用極光的推送功能,並且還說出了必定的理由,領導天然也只有相信了,那就用極光推送吧!php
最近閒來無事,又從新溫習了一下swoole的消息通知功能,雖然在項目開發當時,也曾實現過簡單的操做的,可是此次溫習更加深了學習,配合vb.net進行開發,感受仍是棒棒噠,下面是一套實現過程,若有須要參考,請拿去,不謝!html
首先,個人開發平臺是windows,雖然本人也裝有virtual box虛擬機,可是那玩意兒太耗內存cpu了,開起來搞實在不想搞。因此,就用了cygwin進行配置開發環境搭建,這裏我就不說具體安裝步驟了,給個連接吧,一步步按着操做就好了。 查看php在window下安裝swoole擴展的方法 請點擊。 ps: 若是你win系統裏已經安裝了一套wamp環境,在cygwin中使用php或其餘和win有相同名稱命令時,請記得使用全路徑 如:/bin/php index.php , /bin/find / -name "init*"redis
第二步、編寫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.'; }
記得把它跑起來哦windows
/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'swoole
第四步、你確定不知足於使用php語言去鏈接服務器端,你固然不該該知足!你還可使用windows的cmd命令行嘛,以下:網絡
telnet 127.0.0.1 9501
而後,你會發現,怎麼只輸入了一個字符就發送了。緣由是什麼win的telnet協議之類的,使用send命令,就能夠了。操做爲:按鍵 ctrl + ] ,進入telnet 命令行模式,輸入send aaaddd異步
ok,多開幾個客戶端,看起來會話就能夠了呢(要查看返回的內容,直接按Enter鍵便可,切換回來使用ctrl + ]),來看看服務端都什麼樣子吧:socket
都是有響應的吧,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
到此,打完,收工。因爲異步的調試沒有成功,就此打住吧,之後有興趣再去搞了!