【项目】—— 基于websocket协议的网页版群聊系统

项目简介

  • 使用开源websocket和mongoose框架编写网页版本的群聊即时通信工具
  • 使用HTTP+mongoose+session+MySQL+jsoncpp的技术构成,完成IM工具

项目技术点

  • C++11 STL
  • HTTP协议
  • websocket协议
  • session和cookie理解
  • MySQL c connect
  • 登录注册,session管理
  • mongoose框架框架理解
  • jsoncpp

项目演示

IM聊天界面
登录与注册
注册IM
session+cookie

项目前期准备

了解websocket

WebSocket是一种协议,与HTTP协议一样位于应用层,都是TCP/IP协议的子集。HTTP协议是单向通信协议,只有客户端发起HTTP请求,服务端才会返回数据,那我们来考虑一下,我们在聊天的时候向服务器主动发送信息能够通过HTTP协议实现,但是我们没有办法通过HTTP协议让服务器向我们发送信息,这样就达不到我们想要的聊天效果,因此我就需要借助WebSocket协议了。因为WebSocket协议是双向通信协议,在建立连接之后,客户端和服务器都可以主动向对方发送或接受数据。
WebSocket协议建立的前提需要借助HTTP协议,建立连接之后,持久连接的双向通信就与HTTP协议无关了。

WebSocket协议的目标是在一个独立的持久连接上提供全双工双向通信。客户端和服务器可以向对方主动发送和接受数据。在JS中创建WebSocket后,会有一个HTTP请求发向浏览器以发起请求。在取得服务器响应后,建立的连接会使用HTTP升级将HTTP协议转换为WebSocket协议。也就是说,使用标准的HTTP协议无法实现WebSocket,只有支持那些协议的专门浏览器才能正常工作。

WebSocket是应用层协议,是TCP/IP协议的子集,通过HTTP/1.1协议的101状态码进行握手。也就是说,WebSocket协议的建立需要先借助HTTP协议,在服务器返回101状态码之后,就可以进行websocket 全双工双向通信了,就没有HTTP协议什么事情了

协议升级格式:
  • 客户端请求
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com
  • 服务器回应
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

解释一下几个关键词

  • Connection:Connection必须设置为Upgrade,表示客户端希望连接升级
  • Upgrade:Upgrade必须设置为WebSocket,表示在取得服务器响应之后,使用HTTP升级将HTTP协议转换(升级)为WebSocket协议。
  • Sec-WebSocket-key:随机字符串,用于验证协议是否为WebSocket协议而非HTTP协议
  • Sec-WebSocket-Version:表示使用WebSocket的哪一个版本
  • Sec-WebSocket-Accept:根据Sec-WebSocket-Accept和特殊字符串计算。验证协议是否为WebSocket协议
  • Sec-WebSocket-Location:与Host字段对应,表示请求WebSocket协议的地址
  • HTTP/1.1 101 Switching Protocols:101状态码表示升级协议,在返回101状态码后,HTTP协议完成工作,转换为WebSocket协议。此时就可以进行全双工双向通信了。

具体HTTP升级为WebSocket可参考博客 HTTP升级为WebSocket
其实我的项目为了能够简单一些,并没有自己写将HTTP升级为WebSocket协议的请求,而是借助mongoose框架中的接口进行实现,说到这我们就简单介绍一下mongoose框架

mongoose

Mongoose是c语言写成的网络库。它为TCP、UDP、HTTP、WebSocket、CoAP、MQTT实现了事件驱动型的非阻塞api。其具有以下特性:

  • 跨平台:可在linux/unix macos QNX eCos Windows Android Iphone FreeRtos上运行
  • 原生支持PicoTCP的嵌入式tcp/ip协议栈,支持LWIP嵌入式tcp/ip协议栈
  • 单线程,异步,非阻塞核心与简单的基于事件的API

在运行和占用很小的内存,源代码符合ISO C 和ISO c++规范,使用时,仅需要包含mongoose.c mongoose.h 到我们的项目即可完成整合。Mongoose使嵌入式网络编程快速,健壮,轻松

项目代码编写

这里我想分为四部分来介绍项目的代码实现

  • 首先是实现我们网页的聊天功能
  • 将数据库接入,让我们能够通过代码访问我们的数据库
  • 准备前端页面,为前端页面添加Ajax,使前后端数据json交互
  • 最后就是给我们的项目添加session和cookie
网页聊天功能

在实现之前,我们得来想一想实现一个网页聊天功能我们到底需要做些什么,无非我们需要处理的事情就是4件事:

  • 第一个就是处理客户端发起的HTTP请求,请求能够在我们的网页进行聊天
  • 第二就是客户端发起的将HTTP协议升级为WebSocket协议的请求
  • 第三就是处理客户端发送的聊天信息,由于我们是群聊系统,肯定得让所有在线的客户都收到聊天信息
  • 第四个就是处理有客户端退出,要断开连接的请求

那么接下来我们就紧紧围绕我们需要实现的四个功能来创建我们的网页聊天服务器,为了使代码更加规范和有框架,我将网页聊天服务器封装成了一个类,我们来看看这个类的成员变量
ImServer

  • 给服务器初始化
    初始化
  • 让我们的服务器启动
    服务器启动
  • 接下来就是我们重点了,EventHandler函数的编写,就是按照我们一开始将的四件事来处理我们先看看mongoose框架中是怎么处理的,借鉴其思路来处理我们的问题
    mongoose
  • 我们来看看这个广播功能的实现,广播就是将服务器收到消息通过遍历连接结构体,将信息发给所有建立好连接的客户端,让所有在线的用户都收到消息
    广播功能

走到这我们就实现了服务器最基本功能,可以在网页中通过IP地址和端口号访问我们的服务器,就能够实现聊天功能了

MySQL数据库
  • 在Linux下的mysql中创建数据库和需要的user表
    -
  • 接下来我们就要通过代码来访问数据库, 在此之前我们应该和数据库建立连接,这就需要借助C connector,我们只需要到 https://dev.mysql.com/downloads/connector/c/ 下载对应版本的C connector来使用即可,这里我们也封装一个mysql类,方便之后的使用
  • 尝试链接mysql client

通过 mysql_get_client_info() 函数,来验证我们的引入是否成功

#include <stdio.h>
#include <mysql.h>
int main()
{
	printf("mysql client Version: %s\n", mysql_get_client_info());
	return 0;
}

数据库

  • 建立数据库连接
    数据库连接
  • 往数据库中插入数据
    数据库插入操作
  • 接下来我们来测试一下能否成功插入数据
    测试数据库
    插入数据
准备前端界面,Ajax交互
  • 前端界面我们就不自己写了,上网找一个好看的模板下载之后直接用
  • 接着我们带html文件中加入Ajax,这里不用原生的ajax,使用jQuery ajax,html中引入cdn即可
    ajax代码
  • 增加了登录和注册功能,那我们的服务器应该得有能力处理客户发起的访问登录和注册界面的请求,我们来想一想,我们平时我们要进入一个聊天室,首先应该登录对吧,那我们默认访问的界面就应该是登录界面,那如果服务器收到客户端访问登录界面的处理方式LoginHandler
    登录
  • 注册请求和登录一样处理就行
增加session+cookie
  • 走到上面我们IM聊天室的基本功能都已经完成了,现在就差给聊天室加上session和cookie机制了,这里我给我的聊天室加上的是持久化的cookie,持久化 Cookie 不会在客户端关闭时失效,而是在特定的日期(Expires)或者经过一段特定的时间之后(Max-Age)才会失效,我认为这比较符合我们平时的使用习惯
  • 首先我们创建一个session结构体,这里最重要即是session的ID,是唯一标识一个session,不允许重复,我们平时使用的网页的sessionID都是有特殊方法生成的,我们这里为了简便,且防止重复,我用了时间戳来随机生成一个session的ID
    session
  • 这里我同样封装了一个session类以实现相关功能,该类的成员变量很简单,就是以session结构体定义的一个确定长度数组。
  • 接下来就应该考虑该类应该实现一些什么功能了,首先在一个用户申请访问服务器时,得判断它是一个新用户,还是已经登录过的用户,并尝试获取它的session,若有且合法直接让其登录,并让它进入聊天界面,若该用户无session则默认让其访问登录与注册界面,注册好并登录成功后,则为其创建对应的session,最后在该用户的session生命周期走完之后将该session移除。那简单来说就是四件事:1.获取session 2.检查session 3.创建session 4.销毁session,接下来我们就围绕这四个功能来实现
获取session

获取session

定期检查session是否失效

定期检查

创建session,主要session ID

创建session

销毁session,id = 0

销毁session

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值