1.WebSocket定义
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。
2.与Http协议区别
HTTP:超文本传输协议,首先它是一个协议,并且是基于TCP/IP协议基础之上的应用层协议。TCP/IP协议是传输层协议,主要解决数据如何在网络中传输,HTTP是应用层协议,主要解决如何包装数据。HTTP协议详细规定了浏览器与服务器之间相互通信的规则,是万维网交换信息的基础。HTTP是基于请求-响应形式并且是短连接,并且是无状态的协议。针对其无状态特性,在实际应用中又需要有状态的形式,因此一般会通过session/cookie技术来解决此问题。
Socket:Socket不属于协议范畴,而是一个调用接口(API),Socket是对TCP/IP协议的封装,通过调用Socket,才能使用TCP/IP协议。Socket连接是长连接,理论上客户端和服务器端一旦建立连接将不会主动断开此连接。Socket连接属于请求-响应形式,服务端可主动将消息推送给客户端。
3.聊天室
简单架构:C/S服务端+C/S客户端+B/S客户端
4.实现原理
我们可以尝试让Socket Server透明地支持WebSocket客户端,所谓透明的意思是,服务端开发人员不用关心客户端究竟是什么类型,而是可以统一的接收数据、处理数据、发送数据。为了做到这一点,我们可以构建一个服务端框架,让框架完成透明化的工作,这就要求这个框架做到以下几点:
(1)根据客户端TCP连接请求成功后的第一个消息中是否含有“websocket”标记,来判断其是否为WebSocket客户端。如果客户端的类型是WebSocket,则自动完成以下事情。
(2)自动完成Web Sokects 握手协议。
(3)针对接收到的每个WebSokect数据帧,都能自动将其解析,并从中分离出真正的消息内容。
(4)当您发送消息给WebSokect客户端时,服务端引擎会自动将该消息封装成WebSokect数据帧,然后再发送出去。
5.服务端核心代码实现
小程序市基于StriveEngine组件实现。
启动服务
private void button1_Click(object sender, EventArgs e)
{
try
{
if (this.tcpServerEngine == null)
{
this.tcpServerEngine = NetworkEngineFactory.CreateTextTcpServerEngine(int.Parse(this.textBox_port.Text), new DefaultTextContractHelper("\0"));//DefaultTextContractHelper是StriveEngine内置的ITextContractHelper实现。使用UTF-8对EndToken进行编码。
}
if (this.hasTcpServerEngineInitialized)
{
this.tcpServerEngine.ChangeListenerState(true);
}
else
{
this.InitializeTcpServerEngine();
}
this.ShowListenStatus();
}
catch (Exception ee)
{
MessageBox.Show(ee.Message);
}
}
发送文本
private void button2_Click(object sender, EventArgs e)
{
try
{
IPEndPoint client = (IPEndPoint)this.comboBox1.SelectedItem;
if (client == null)
{
MessageBox.Show("没有选中任何在线客户端!");
return;
}
if (!this.tcpServerEngine.IsClientOnline(client))
{
MessageBox.Show("目标客户端不在线!");
return;
}
string msg = this.textBox_msg.Text + "\0";// "\0" 表示一个消息的结尾
byte[] bMsg = System.Text.Encoding.UTF8.GetBytes(msg);//消息使用UTF-8编码
this.tcpServerEngine.SendMessageToClient(client, bMsg);
}
catch (Exception ee)
{
MessageBox.Show(ee.Message);
}
}
6.C/S客户端核心代码实现
连接服务端
private void button3_Click(object sender, EventArgs e)
{
try
{
//初始化并启动客户端引擎(TCP、文本协议)
this.tcpPassiveEngine = NetworkEngineFactory.CreateTextTcpPassiveEngine(this.textBox_IP.Text, int.Parse(this.textBox_port.Text), new DefaultTextContractHelper("\0"));
this.tcpPassiveEngine.MessageReceived += new CbDelegate<System.Net.IPEndPoint, byte[]>(tcpPassiveEngine_MessageReceived);
this.tcpPassiveEngine.AutoReconnect = true;//启动掉线自动重连
this.tcpPassiveEngine.ConnectionInterrupted += new CbDelegate(tcpPassiveEngine_ConnectionInterrupted);
this.tcpPassiveEngine.ConnectionRebuildSucceed += new CbDelegate(tcpPassiveEngine_ConnectionRebuildSucceed);
this.tcpPassiveEngine.Initialize();
this.button2.Enabled = true;
this.button3.Enabled = false;
MessageBox.Show("连接成功!");
}
catch (Exception ee)
{
MessageBox.Show(ee.Message);
}
}
发送文本
private void button2_Click(object sender, EventArgs e)
{
string msg = this.textBox_msg.Text + "\0";// "\0" 表示一个消息的结尾
byte[] bMsg = System.Text.Encoding.UTF8.GetBytes(msg);//消息使用UTF-8编码
this.tcpPassiveEngine.SendMessageToServer(bMsg);
}
7.B/S客户端实现
连接服务端
function connect() {
var host = "ws://" + $("serverIP").value + ":" + $("serverPort").value + "/"
socket = new WebSocket(host);
try {
socket.onopen = function (msg) {
$("btnConnect").disabled = true;
alert("连接成功!");
};
socket.onmessage = function (msg) {
if (typeof msg.data == "string") {
displayContent(msg.data);
}
else {
alert("非文本消息");
}
};
socket.onclose = function (msg) { alert("socket closed!") };
}
catch (ex) {
log(ex);
}
}
发送文本
function send() {
var msg = $("sendText").value + '\0'
socket.send(msg);
}
8.效果图
启动服务端监听端口号9000,开启多个客户端实现连接,发送消息,连接状态是保持的,可以实现服务端和客户端互相推送消息!