C# 使用WebSocket创建聊天室案例
WebSocket介绍
WebSocket是HTML5开始提供的一种在单个 TCP 连接上进行全双工通讯的协议
在WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据
当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据.
其实WebSocket与Socket区别不大,只是客户端是在浏览器上实现的,替代了传统的轮询机制,减少带宽和资源
C#中WebSocket定义事件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WebSocketsServer
{
/// <summary>
/// 声明新连接处理事件
/// </summary>
/// <param name=”loginName”></param>
/// <param name=”e”></param>
public delegate void NewConnection_EventHandler(string loginName, EventArgs args);
/// <summary>
/// 声明接收数据处理事件
/// </summary>
/// <param name=”sender”></param>
/// <param name=”message”></param>
/// <param name=”args”></param>
public delegate void DataReceive_EventHandler(object sender, string message, EventArgs args);
/// <summary>
/// 声明断开连接处理事件
/// </summary>
/// <param name=”sender”></param>
/// <param name=”args”></param>
public delegate void Disconncetion_EventHandler(object sender, string message, EventArgs args);
}
WebSocket服务端实现代码
WebSocketServer代码
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace WebSocketsServer
{
/// <summary>
/// Socket服务端
/// </summary>
public class WebSocketServer : IDisposable
{
#region 私有变量
/// <summary>
/// ip
/// </summary>
private string _ip = string.Empty;
/// <summary>
/// 端口
/// </summary>
private int _port = 0;
/// <summary>
/// 服务器地址
/// </summary>
private string _serverLocation = string.Empty;
/// <summary>
/// Socket对象
/// </summary>
private Socket _socket = null;
/// <summary>
/// 监听的最大连接数
/// </summary>
private int maxListenConnect = 10;
/// <summary>
/// 是否关闭Socket对象
/// </summary>
private bool isDisposed = false;
private Logger logger = null;
/// <summary>
/// buffer缓存区字节数
/// </summary>
private int maxBufferSize = 0;
/// <summary>
/// 第一个字节,以0x00开始
/// </summary>
private byte[] FirstByte;
/// <summary>
/// 最后一个字节,以0xFF结束
/// </summary>
private byte[] LastByte;
#endregion
#region 声明Socket处理事件
/// <summary>
/// Socket新连接事件
/// </summary>
public event NewConnection_EventHandler NewConnectionHandler;
/// <summary>
/// Socket接收消息事件
/// </summary>
public event DataReceive_EventHandler DataReceiveHandler;
/// <summary>
/// Socket断开连接事件
/// </summary>
public event Disconncetion_EventHandler DisconnectionHandler;
#endregion
/// <summary>
/// 存放SocketConnection集合
/// </summary>
List<SocketConnection> SocketConnections = new List<SocketConnection>();
#region 构造函数
public WebSocketServer()
{
this._ip = GetLocalMachineIPAddress().ToString();
this._port = 9000;
this._serverLocation = string.Format(“ws://{0}:{1}”, this._ip, this._port);
Initialize();
}
public WebSocketServer(string ip, int port)
{
this._ip = ip;
this._port = port;
this._serverLocation = string.Format(“ws://{0}:{1}”, this._ip, this._port);
Initialize();
}
public WebSocketServer(string ip, int port, string serverLocation)
{
this._ip = ip;
this._port = port;
this._serverLocation = serverLocation;
Initialize();
}
#endregion
/// <summary>
/// 初始化私有变量
/// </summary>
private void Initialize()
{
isDisposed = false;
logger = new Logger()
{
LogEvents = true
};
maxBufferSize = 1024 * 1024;
maxListenConnect = 500;
FirstByte = new byte[maxBufferSize];
LastByte = new byte[maxBufferSize];
FirstByte[0] = 0x00;
LastByte[0] = 0xFF;
}
/// <summary>
/// 开启服务
/// </summary>
public void StartServer()
{
try
{
//实例化套接字
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//创建IP对象
IPAddress address = GetLocalMachineIPAddress();
//创建网络端点,包括ip和port
IPEndPoint endPoint = new IPEndPoint(address, _port);
//将socket与本地端点绑定
_socket.Bind(endPoint);
//设置最大监听数
_socket.Listen(maxListenConnect);
logger.Log(string.Format(“聊天服务器启动。监听地址:{0}, 端口:{1}”, this._ip, this._port));
logger.Log(string.Format(“WebSocket服务器地址: ws://{0}:{1}”, this._ip, this._port));
//开始监听客户端
Thread thread = new Thread(ListenClientConnect);
thread.Start();
}
catch (Exception ex)
{
logger.Log(ex.Message);
}
}
/// <summary>
/// 监听客户端连接
/// </summary>
private void ListenClientConnect()
{
try
{
while (true)
{
//为新建连接创建的Socket
Socket socket = _socket.Accept();
if (socket != null)
{
//线程不休眠的话,会导致回调函数的AsyncState状态出异常
Thread.Sleep(100);
SocketConnection socketConnection = new SocketConnection(this._ip, this._port, this._serverLocation)
{
ConnectionSocket = socket
};
//绑定事件
socketConnection.NewConnectionHandler += SocketConnection_NewConnectionHandler;
socketConnection.DataReceiveHandler += SocketConnection_DataReceiveHandler;
socketConnection.DisconnectionHandler += SocketConnection_DisconnectionHandler;
//从开始连接的Socket中异步接收消息
socketConnection.ConnectionSocket.BeginReceive(socketConnection.receivedDataBuffer,
0, socketConnection.receivedDataBuffer.Length,
0, new AsyncCallback(socketConnection.ManageHandshake),
socketConnection.ConnectionSocket.Available);
//存入集合,以便在Socket发送消息时发送给所有连接的Socket套接字
SocketConnections.Add(socketConnection);
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
/// <summary>
/// SocketConnection监听的新连接事件
/// </summary>
/// <param name=”loginName”></param>
/// <param name=”args”></param>
private void SocketConnection_NewConnectionHandler(string loginName, EventArgs args)
{
NewConnectionHandler?.Invoke(loginName, EventArgs.Empty);
}
/// <summary>
/// SocketConnection监听的消息接收事件
/// </summary>
/// <param name=”sender”></param>
/// <param name=”msgData”></param>
/// <param name=”args”></param>
private void SocketConnection_DataReceiveHandler(object sender, string msgData, EventArgs args)
{
//新用户连接进来时显示欢迎信息
//SocketConnection socketConnection = sender as SocketConnection;
Send(msgData);
}
/// <summary>
/// SocketConnection监听的断开连接事件
/// </summary>
/// <param name=”sender”></param>
/// <param name=”args”></param>
private void SocketConnection_DisconnectionHandler(object sender, string message, EventArgs args)
{
if (sender is SocketConnection socket)
{
Send(message);
socket.ConnectionSocket.Close();
SocketConnections.Remove(socket);
}
}
/// <summary>
/// 发送消息
/// </summary>
/// <param name=”message”></param>
public void Send(string message)
{
//给所有连接上的发送消息
foreach (SocketConnection socket in SocketConnections)
{
if (!socket.ConnectionSocket.Connected)
{
continue;
}
try
{
if (socket.IsDataMasked)
{
DataFrame dataFrame = new DataFrame(message);
socket.ConnectionSocket.Send(dataFrame.GetBytes());
}
else
{
socket.ConnectionSocket.Send(FirstByte);
socket.ConnectionSocket.Send(Encoding.UTF8.GetBytes(message));
socket.ConnectionSocket.Send(LastByte);
}
}
catch (Exception ex)
{
logger.Log(ex.Message);
}
}
}
/// <summary>
/// 获取当前主机的IP地址
/// </summary>
/// <returns></returns>
private IPAddress GetLocalMachineIPAddress()
{
//获取计算机主机名
string hostName = Dns.GetHostName();
//将主机名解析为IPHostEntry
IPHostEntry hostEntry = Dns.GetHostEntry(hostName);
foreach (IPAddress address in hostEntry.AddressList)
{
//IP4寻址协议
if (address.AddressFamily == AddressFamily.InterNetwork)
{
return address;
}
}
return hostEntry.AddressList[0];
}
~WebSocketServer()
{
Close();
}
public void Dispose()
{
Close();
}
public void Close()
{
if (!isDisposed)
{
isDisposed = true;
if (_socket != null)
{
_socket.Close();
}
foreach (SocketConnection socketConnection in SocketConnections)
{
socketConnection.ConnectionSocket.Close();
}
SocketConnections.Clear();
GC.SuppressFinalize(this);
}
}
}
}