由于RabbitMQ中只有队列(queue)才能存储信息,所以用RabbitMQ实现超大用户级别(百万计)的消息在/离线收发需要对每一个用户创建一个永久队列。

但是RabbitMQ节点内存有限,经测试后发现节点集群也无法满足数百万用户队列收发数据的要求,所以最终决定采用数据库辅助实现该功能。

一、数据库结构

user_list数据库下有4张表:user_info、group_info、groupmember_info、message_info。

user_info表中含有username(主键,非空,VARCHAR(50))、password(非空,VARCHAR(50))、routingkey(非空,VARCHAR(50))、has_queue(INT UNSIGNED)四个字段。

group_info表中含有groupname(主键,非空,VARCHAR(50))、password(非空,VARCHAR(50))、creator(非空,VARCHAR(50))三个字段。

groupmember_info表中含有username(主键,非空,VARCHAR(50))、groupname(主键,非空,VARCHAR(50))两个字段。

message_info表中含有sendtime(非空,VARCHAR(50))、body(非空,VARCHAR(300)),receiver(非空,VARCHAR(50))、sender(非空,VARCHAR(100))四个字段。

二、客户端结构

1、文件夹创建以及包依赖安装:

dotnet new console --name Client
mv Client/Program.cs Client/Client.cs
cd Client
dotnet add package RabbitMQ.Client
dotnet add package MySql.Data
dotnet restore 2、项目结构 Client.cs(主程序):
using RabbitMQ.Client;
using MySql.Data.MySqlClient; namespace Client
{
class Client
{
static void Main(string[] args)
{
// 连接数据库
string connStr = "Database=user_list;datasource=127.0.0.1;port=3306;user=root;pwd=123456;";
MySqlConnection sqlConn = new MySqlConnection(connStr); sqlConn.Open(); // 连接RabbitMQ
var factory = new ConnectionFactory() { HostName = "dev.corp.wingoht.com", VirtualHost = "cd", UserName = "ishowfun", Password = "" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
// 用户登录,并获取离线消息
UserInfo user = UserLogin.Login(sqlConn); // 监听在线消息
Consumer.StartListening(channel, sqlConn, user); // 监听按钮事件,调用不同的客户端功能
KeyListening.StartListening(channel, sqlConn, user); // 退出登录
UserLogout.Logout(channel, sqlConn, user);
} // 释放数据库连接
sqlConn.Close();
}
}
}

 UserLogin.cs:

using System;
using MySql.Data.MySqlClient; namespace Client
{
class UserLogin
{
public static UserInfo Login(MySqlConnection conn)
{
UserInfo user = new UserInfo(); // 用户名输入
Console.Write("Please enter your username: ");
user.Username = Console.ReadLine();
while (user.Username.Contains(",") || user.Username.Contains(" "))
{
Console.WriteLine("Error: Username can not contain \",\"! and \" \"");
Console.Write("Please enter your username again: ");
user.Username = Console.ReadLine();
} MySqlCommand cmd = new MySqlCommand("select * from user_info where username='" + user.Username + "'", conn);
MySqlDataReader reader = cmd.ExecuteReader(); // 判断该用户是否已经注册
if (reader.Read())
{
// 已注册用户登录
user.IsNewUser = true; // 验证密码
Console.Write("Please enter your password: ");
user.Password = reader.GetString("password");
while (user.Password != Console.ReadLine())
{
Console.WriteLine("Error: Username and password do not match!");
Console.Write("Please enter your password again: ");
}
Console.WriteLine("Welcome back, {0}!", user.Username);
Console.WriteLine("-------------------------------------"); // 获取当前用户的路由键
user.RoutingKey = reader.GetString("routingkey");
reader.Close(); // 读取离线消息
cmd = new MySqlCommand("select * from message_info where receiver='" + user.Username + "'", conn);
reader = cmd.ExecuteReader();
Console.WriteLine("Unread Message: ");
while (reader.Read())
{
string sender = reader.GetString("sender");
string sendTime = reader.GetString("sendtime");
string content = reader.GetString("body");
string[] splitSender = sender.Split(" ");
if (splitSender.Length == )
{
Console.WriteLine("Sender: {0}, SendTime: {1}, Content: {2}", sender, sendTime, content);
}
else
{
sender = splitSender[];
string group = splitSender[];
Console.WriteLine("Sender: {0} from {1}, SendTime: {2}, Content: {3}", sender, group, sendTime, content);
}
}
reader.Close(); // 删除已处理的离线消息
cmd = new MySqlCommand("delete from message_info where receiver=@re", conn);
cmd.Parameters.AddWithValue("re", user.Username); cmd.ExecuteNonQuery();
}
else
{
// 新用户注册并登录
user.IsNewUser = false;
reader.Close();
Console.WriteLine("Welcome, new user!"); // 设置密码
Console.Write("Please set your password: ");
user.Password = Console.ReadLine();
Console.Write("Please confirm your password: ");
while (user.Password != Console.ReadLine())
{
Console.WriteLine("Error: Confirmation failure!");
Console.Write("Please set your password again: ");
user.Password = Console.ReadLine();
Console.Write("Please confirm your password: ");
} // 生成该用户的加密路由键,并保证该路由键唯一
user.RoutingKey = GenerateKey.GenerateRandomString();
cmd = new MySqlCommand("select * from user_info where routingkey='" + user.RoutingKey + "'", conn);
reader = cmd.ExecuteReader();
while (reader.Read())
{
reader.Close();
user.RoutingKey = GenerateKey.GenerateRandomString();
reader = cmd.ExecuteReader();
} reader.Close();
} Console.WriteLine("-------------------------------------");
return user;
}
}
}

 UserInfo.cs:

namespace Client
{
class UserInfo
{
// 唯一用户名
public string Username { get; set; } // 登录密码
public string Password { get; set; } // 加密路由键
public string RoutingKey { get; set; } // 是否为新用户
public bool IsNewUser { get; set; }
}
}

 GenerateKey.cs: 

using System;

namespace Client
{
class GenerateKey
{
// 字符串中字符的取值范围
private static char[] constant =
{
'','','','','','','','','','',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
}; // 生成指定长度的随机字符串
public static string GenerateRandomString(int len)
{
System.Text.StringBuilder newRandom = new System.Text.StringBuilder();
Random rd = new Random();
for (int i = ; i < len; i++)
{
newRandom.Append(constant[rd.Next()]);
}
return newRandom.ToString();
}
}
}

 Consumer.cs:

using System;
using System.Text; using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using MySql.Data.MySqlClient; namespace Client
{
class Consumer
{
public static void StartListening(IModel channel, MySqlConnection conn, UserInfo user)
{
// 交换机声明
channel.ExchangeDeclare(exchange: "topic_message", type: "topic"); // 队列创建与绑定
channel.QueueDeclare(queue: user.RoutingKey,
durable: true,
exclusive: false,
autoDelete: false,
arguments: null); channel.QueueBind(queue: user.RoutingKey,
exchange: "topic_message",
routingKey: user.RoutingKey); var consumer = new EventingBasicConsumer(channel); // 处理收到的消息
consumer.Received += (model, ea) =>
{
var body = ea.Body;
string message = Encoding.UTF8.GetString(body);
string[] splitRes = message.Trim().Split(",");
string sendTime = splitRes[];
string content = splitRes[];
string[] splitSender = splitRes[].Split(" ");
if (splitRes.Length > )
{
for (int i = ; i < splitRes.Length; i++)
content = content + "," + splitRes[i];
} Console.WriteLine();
if (splitSender.Length == )
{
string sender = splitRes[];
Console.WriteLine("Sender: {0}, SendTime: {1}, Content: {2}", sender, sendTime, content);
}
else
{
string sender = splitSender[];
string group = splitSender[];
Console.WriteLine("Sender: {0} from {1}, SendTime: {2}, Content: {3}", sender, group, sendTime, content);
}
}; channel.BasicConsume(queue: user.RoutingKey,
autoAck: true,
consumer: consumer); MySqlCommand cmd; // 更新数据库
if (user.IsNewUser)
{
// 向数据库声明该用户已经拥有了队列,可以直接在线发送
cmd = new MySqlCommand("update user_info set has_queue=1 where username=@uid", conn);
cmd.Parameters.AddWithValue("uid", user.Username); cmd.ExecuteNonQuery();
}
else
{
// 防止注入地插入新用户数据
cmd = new MySqlCommand("insert into user_info set username=@uid,password=@pwd,routingkey=@rk,has_queue=1", conn);
cmd.Parameters.AddWithValue("uid", user.Username);
cmd.Parameters.AddWithValue("pwd", user.Password);
cmd.Parameters.AddWithValue("rk", user.RoutingKey); cmd.ExecuteNonQuery();
} Console.WriteLine("{0} Start Listening!", user.Username);
Console.WriteLine("-------------------------------------");
}
}
}

 KeyListening.cs:

using System;

using RabbitMQ.Client;
using MySql.Data.MySqlClient; namespace Client
{
class KeyListening
{
public static void StartListening(IModel channel, MySqlConnection conn, UserInfo user)
{
MQHelper.HelpTip();
Console.WriteLine("-------------------------------------");
ConsoleKeyInfo keyPressed;
bool escFlag = false; while (true)
{ keyPressed = Console.ReadKey();
Console.WriteLine();
Console.WriteLine("-------------------------------------");
switch (keyPressed.Key)
{
// 0: 显示帮助信息
case ConsoleKey.D0:
MQHelper.HelpTip();
break;
// 1: 创建群组
case ConsoleKey.D1:
MQHelper.CreateGroup(conn, user);
break;
// 2: 申请加入群组
case ConsoleKey.D2:
MQHelper.JoinGroup(conn, user);
break;
// 3: 退出群组
case ConsoleKey.D3:
MQHelper.LeaveGroup(conn, user);
break;
// 4: 显示群组信息
case ConsoleKey.D4:
MQHelper.ShowGroup(conn, user);
break;
// 5: 单播
case ConsoleKey.D5:
MQHelper.BasicSend(channel, conn, user);
break;
// 6: 组播
case ConsoleKey.D6:
MQHelper.GroupSend(channel, conn, user);
break;
// ESC: 退出
case ConsoleKey.Escape:
escFlag = true;
break;
// 无意义按键
default:
Console.WriteLine("Error: Invalid press!");
break;
} Console.WriteLine("-------------------------------------"); if (escFlag)
break;
}
}
}
}

 MQHelper.cs:

using System;
using System.Text;
using System.Collections.Generic; using RabbitMQ.Client;
using MySql.Data.MySqlClient; namespace Client
{
// 该类包含了按钮监听事件触发的各项功能的实现
class MQHelper
{
#region 显示帮助信息
public static void HelpTip()
{
// 显示各按键对应功能
Console.WriteLine("Function Press:");
Console.WriteLine("[0]: Help");
Console.WriteLine("[1]: Create group");
Console.WriteLine("[2]: Join group");
Console.WriteLine("[3]: Leave group");
Console.WriteLine("[4]: Show groups");
Console.WriteLine("[5]: BasicSend");
Console.WriteLine("[6]: GroupSend");
Console.WriteLine("[ESC]: Log out");
}
#endregion #region 创建群组
public static void CreateGroup(MySqlConnection conn, UserInfo user)
{
// 设置群组名称以及加入密码
Console.Write("Please set the group name: ");
string groupName = Console.ReadLine();
MySqlCommand groupCmd = new MySqlCommand("select * from group_info where groupname='" + groupName + "'", conn);
MySqlDataReader groupReader = groupCmd.ExecuteReader(); if (groupReader.Read())
{
groupReader.Close();
Console.WriteLine("Error: This group name already exists!");
}
else
{
groupReader.Close(); Console.Write("Please set the password: ");
string pwd = Console.ReadLine();
Console.Write("Please confirm the password: ");
while (pwd != Console.ReadLine())
{
Console.WriteLine("Error: Confirmation failure!");
Console.Write("Please set the password again: ");
pwd = Console.ReadLine();
Console.Write("Please confirm the password: ");
} // 将群组信息插入数据库
groupCmd = new MySqlCommand("insert into group_info set groupname=@gid,password=@pwd,creator=@cr", conn);
groupCmd.Parameters.AddWithValue("gid", groupName);
groupCmd.Parameters.AddWithValue("pwd", pwd);
groupCmd.Parameters.AddWithValue("cr", user.Username); groupCmd.ExecuteNonQuery(); groupCmd = new MySqlCommand("insert into groupmember_info set groupname=@gid,username=@uid", conn);
groupCmd.Parameters.AddWithValue("gid", groupName);
groupCmd.Parameters.AddWithValue("uid", user.Username); groupCmd.ExecuteNonQuery(); Console.WriteLine("Successfully create the group!");
}
}
#endregion #region 申请加入群组
public static void JoinGroup(MySqlConnection conn, UserInfo user)
{
// 输入要加入的群名
Console.Write("Please enter the group name: ");
string groupName = Console.ReadLine();
MySqlCommand groupCmd = new MySqlCommand("select * from group_info where groupname='" + groupName + "'", conn);
MySqlDataReader groupReader = groupCmd.ExecuteReader(); // 判断该群是否存在
if (groupReader.Read())
{
// 验证加入密码
string pwd = groupReader.GetString("password");
groupReader.Close(); Console.Write("Please enter your password: ");
if (pwd != Console.ReadLine())
{
Console.WriteLine("Error: Username and password do not match!");
}
else
{
groupCmd = new MySqlCommand("select * from groupmember_info where groupname='" + groupName + "' and username='" + user.Username + "'", conn);
groupReader = groupCmd.ExecuteReader(); // 判断该用户是否已经在这个群中
if (groupReader.Read())
{
groupReader.Close();
Console.WriteLine("Error: You already join the group!");
}
else
{
// 加入该群,并更新数据库信息
groupReader.Close();
groupCmd = new MySqlCommand("insert into groupmember_info set groupname=@gid,username=@uid", conn);
groupCmd.Parameters.AddWithValue("gid", groupName);
groupCmd.Parameters.AddWithValue("uid", user.Username); groupCmd.ExecuteNonQuery();
Console.WriteLine("Successfully join the group!");
}
}
}
else
{
groupReader.Close();
Console.WriteLine("Error: This group name does not exist!");
}
}
#endregion #region 退出群组
public static void LeaveGroup(MySqlConnection conn, UserInfo user)
{
// 输入要退出群的名称
Console.Write("Please enter the group name: ");
string groupName = Console.ReadLine();
MySqlCommand groupCmd = new MySqlCommand("select * from groupmember_info where groupname='" + groupName + "' and username='" + user.Username + "'", conn);
MySqlDataReader groupReader = groupCmd.ExecuteReader(); // 判断你是否在这个群中
if (groupReader.Read())
{
// 退出该群,并更新数据库信息
groupReader.Close();
groupCmd = new MySqlCommand("delete from groupmember_info where groupname=@gid and username=@uid", conn);
groupCmd.Parameters.AddWithValue("gid", groupName);
groupCmd.Parameters.AddWithValue("uid", user.Username);
groupCmd.ExecuteNonQuery();
Console.WriteLine("Successfully leave the group!");
}
else
{
groupReader.Close();
Console.WriteLine("Error: You didn't join the group!");
}
}
#endregion #region 显示群组信息
public static void ShowGroup(MySqlConnection conn, UserInfo user)
{
MySqlCommand groupCmd = new MySqlCommand("select * from groupmember_info where username='" + user.Username + "'", conn);
MySqlDataReader groupReader = groupCmd.ExecuteReader(); // 显示加入的所有群名称
while (groupReader.Read())
{
Console.WriteLine(groupReader.GetString("groupname"));
}
groupReader.Close();
}
#endregion #region 单播
public static void BasicSend(IModel channel, MySqlConnection conn, UserInfo user)
{
// 输入收信人用户名
Console.Write("Please enter the receiver: ");
string receiver = Console.ReadLine();
Console.WriteLine("-------------------------------------"); // 输入待发送的消息
Console.WriteLine("Please enter the message: ");
string content = Console.ReadLine();
Console.WriteLine("-------------------------------------");
MySqlCommand sendCmd = new MySqlCommand("select * from user_info where username='" + receiver + "'", conn);
MySqlDataReader sendReader = sendCmd.ExecuteReader(); bool user_flag = sendReader.Read(); // 判断是否存在该收信人
if (user_flag)
{
string receiverKey = sendReader.GetString("routingkey");
int hasQueue = sendReader.GetInt32("has_queue");
string sendTime = DateTime.Now.ToString();
string message = user.Username + "," + sendTime + "," + content;
var body = Encoding.UTF8.GetBytes(message); sendReader.Close(); // 目标队列存在,则直接发布信息;否则将信息数据存入数据库
if (hasQueue == )
{
// 在线发布消息
var properties = channel.CreateBasicProperties();
properties.Persistent = true; channel.BasicPublish(exchange: "topic_message",
routingKey: receiverKey,
basicProperties: properties,
body: body);
}
else
{
// 离线发布消息
sendCmd = new MySqlCommand("insert into message_info set sendtime=@st,body=@body,receiver=@re,sender=@se", conn);
sendCmd.Parameters.AddWithValue("st", sendTime);
sendCmd.Parameters.AddWithValue("body", content);
sendCmd.Parameters.AddWithValue("re", receiver);
sendCmd.Parameters.AddWithValue("se", user.Username); sendCmd.ExecuteNonQuery();
}
Console.WriteLine("You sent [ {0} ] to {1} at {2}.", content, receiver, sendTime);
}
else
{
sendReader.Close();
Console.WriteLine("Error: The receiver does not exist!");
}
}
#endregion #region 组播
public static void GroupSend(IModel channel, MySqlConnection conn, UserInfo user)
{
// 输入在那个群组中发布消息
Console.Write("Please enter the receiver: ");
string group = Console.ReadLine();
Console.WriteLine("-------------------------------------"); // 输入待发布消息
Console.WriteLine("Please enter the message: ");
string content = Console.ReadLine();
Console.WriteLine("-------------------------------------"); // 读取群组中的所有成员
MySqlCommand sendCmd = new MySqlCommand("select * from groupmember_info where groupname='" + group + "'", conn);
MySqlDataReader sendReader = sendCmd.ExecuteReader();
List<string> memberList = new List<string>();
while (sendReader.Read())
{
memberList.Add(sendReader.GetString("username"));
}
sendReader.Close(); string sender = user.Username + " " + group;
string sendTime = DateTime.Now.ToString(); // 交换机声明
channel.ExchangeDeclare(exchange: "topic_message", type: "topic"); var properties = channel.CreateBasicProperties();
properties.Persistent = true; // 逐个处理成员,在线用户在线发送消息,离线用户离线发送消息
foreach (string member in memberList)
{
sendCmd = new MySqlCommand("select * from user_info where username='" + member + "'", conn);
sendReader = sendCmd.ExecuteReader(); sendReader.Read();
string receiverKey = sendReader.GetString("routingkey");
int hasQueue = sendReader.GetInt32("has_queue");
string message = sender + "," + sendTime + "," + content;
var body = Encoding.UTF8.GetBytes(message);
sendReader.Close(); // 目标队列存在,则直接发布信息;否则将信息数据存入数据库
if (hasQueue == )
{
// 在线发送消息
channel.BasicPublish(exchange: "topic_message",
routingKey: receiverKey,
basicProperties: properties,
body: body);
}
else
{
// 离线发送消息
sendCmd = new MySqlCommand("insert into message_info set sendtime=@st,body=@body,receiver=@re,sender=@se", conn);
sendCmd.Parameters.AddWithValue("st", sendTime);
sendCmd.Parameters.AddWithValue("body", content);
sendCmd.Parameters.AddWithValue("re", member);
sendCmd.Parameters.AddWithValue("se", sender); sendCmd.ExecuteNonQuery();
}
} Console.WriteLine("You sent [ {0} ] to {1} at {2}.", content, group, sendTime);
}
#endregion
}
}

 UserLogout.cs:

using System;

using RabbitMQ.Client;
using MySql.Data.MySqlClient; namespace Client
{
class UserLogout
{
public static void Logout(IModel channel, MySqlConnection conn, UserInfo user)
{
Console.WriteLine("Goodbye, {0}!", user.Username); // 删除队列,并更新数据库,表明后面发送的消息应该转为离线发送
channel.QueueDelete(user.RoutingKey);
MySqlCommand cmd = new MySqlCommand("update user_info set has_queue=0 where username=@uid", conn);
cmd.Parameters.AddWithValue("uid", user.Username); cmd.ExecuteNonQuery();
}
}
}
百度云链接:https://pan.baidu.com/s/1Y93rcqnsv1cA9ZIxH2xrBw 密码:zfc5

利用RabbitMQ、MySQL实现超大用户级别的消息在/离线收发的更多相关文章

  1. 转: 利用RabbitMQ、MySQL实现超大用户级别的消息在/离线收发

    由于RabbitMQ中只有队列(queue)才能存储信息,所以用RabbitMQ实现超大用户级别(百万计)的消息在/离线收发需要对每一个用户创建一个永久队列. 但是RabbitMQ节点内存有限,经测试 ...

  2. mysql事务之一:MySQL数据库事务隔离级别(Transaction Isolation Level)及锁的实现原理

    一.数据库隔离级别 数据库隔离级别有四种,应用<高性能mysql>一书中的说明: 然后说说修改事务隔离级别的方法: 1.全局修改,修改mysql.ini配置文件,在最后加上 1 #可选参数 ...

  3. 【MySQL】事务隔离级别及ACID

    注:begin或start transaction并不是一个事务的起点,而是在执行它们之后的第一个操作InnoDB表的语句,事务才真正开始.start transaction with consist ...

  4. 一文读懂MySQL的事务隔离级别及MVCC机制

    回顾前文: 一文学会MySQL的explain工具 一文读懂MySQL的索引结构及查询优化 (同时再次强调,这几篇关于MySQL的探究都是基于5.7版本,相关总结与结论不一定适用于其他版本) 就软件开 ...

  5. MySQL创建一个用户,指定一个数据库 授权

    Mysql 创建一个用户 hail,密码 hail,指定一个数据库 haildb 给 hail mysql -u root -ppassworduse mysql;insert into user(h ...

  6. 转:mysql 创建一个用户,指定一个数据库

    转自:http://blog.sina.com.cn/s/blog_8c2525390101h0dv.html mysql 创建一个用户 hail,密码 hail,指定一个数据库 haildb 给 h ...

  7. MySQL创建新用户、增加账户的2种方法及使用实例

    可以用两种方式创建MySQL账户:1.使用GRANT语句2.直接操作MySQL授权表最好的方法是使用GRANT语句,因为这样更精确,错误少.创建超级用户: mysql> GRANT ALL PR ...

  8. MySQL—概念,用户的创建,主键,外键,数据类型,表格创建

    MySQL DBMS,MySQL的概念,数据库分类,以前MySQL的部署中的一些概念 #DBMS:数据库管理系统,用于管理数据库的大型软件.mysql就是dbms的一种 #Mysql:是用于管理文件的 ...

  9. MySQL事务及隔离级别详解

    MySQL事务及隔离级别详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.MySQL的基本架构 MySQL的基本架构可以分为三块,即连接池,核心功能层,存储引擎层. 1> ...

随机推荐

  1. gulp 前端构建工具入门

    gulp 前端构建工具入门 标签(空格分隔): gulp 1. 安装gulp npm i -g gulp 2. 创建gulp项目 2.1 Hello world 使用npm init初始化项目文件夹. ...

  2. 【转】Linux中/etc/profile,/etc/bashrc,~/.profile,~/.bashrcd的区别

    //因为在原文章中博主说以下内容是网友说的,所以我就只加个转了,找不到原作者 /etc/profile,/etc/bashrc 是系统全局环境变量设定 ~/.profile,~/.bashrc用户家目 ...

  3. 第一周 day1 Python学习笔记

    为什么要学习Python? Python擅长的领域 1. python2.x中不支持中文编码,默认编码格式为ASCII码,而python3.x中支持Unicode编码,支持中文,变量名可以为中文,如: ...

  4. monodevelop 基础用法

    1.mono快捷键      CTRL+K  删除光标所在行的该行后面的代码 CTRL + ALT +C  注释/不注释该行 CTRL+ DOWN  像鼠标滚轮一样向下拖 CTRL + UP 像鼠标滚 ...

  5. bzoj3609 [Heoi2014]人人尽说江南好

    Description 小 Z 是一个不折不扣的 ZRP(Zealot Round-game Player,回合制游戏狂热玩家),最近他 想起了小时候在江南玩过的一个游戏.    在过去,人们是要边玩 ...

  6. Swift编程语言学习1.1——常量与变量

    常量和变量把一个名字(比方maximumNumberOfLoginAttempts或者welcomeMessage)和一个指定类型的值(比方数字10或者字符串"Hello")关联起 ...

  7. mint-ui 填坑之路

    swipe组件 因为项目加载eslint的缘故也就没有像之前的项目一样引用swiper框架.这个轮播图的组件文档实在是不敢恭维(尽管其他的文档也好不到哪里去),官方给出的参数真是少的可怜,一些方法也并 ...

  8. C# Path类 FileStream(文件流) 与 File(文件) 读取的区别

    1.采用文件流读取数据是一点一点从文件中读取数据对内存的压力相对较小;而采用文件读取数据是一下全部读取过来对内存造成的压力相对较大 2.File读取: string str = @"E:\Q ...

  9. 应对STM32 Cortex-M3 Hard Fault异常

    STM32 Cortex-M3 Hard Fault Hard fault (硬错误,也有译为硬件错误的)是在STM32(如无特别说明,这里的STM32指的是Cortex-M3的核)上编写程序中所产生 ...

  10. Java语言实现简单的登陆注册

    1.登录注册 1.1数据库设计 create table USER_INFO( id number not null, name ) not null, pass ) )insert into USE ...