目录

介绍

背景

1. WebSocket

2.服务器发送事件(SSE)

3.永远的Frame

4.轮询

5.长轮询

场景描述

先决条件

使用代码

第1步:创建项目

步骤2:打开PM以安装依赖项文件

第3步:删除旧依赖关系的指令

第4步:安装必要的依赖项文件的说明

第5步:启动类

第6步:根据我们的场景组织数据库

第7步:创建Hub类

步骤8:创建文件夹并将其命名为Hubs然后创建简单类并将其命名为“MyHub.cs”

规则和约定

提示


  • 下载项目 - 4.35 MB

介绍

如今,由于信息量的增加和实时实现数据的必要性,我们需要技术来满足我们在这个问题上的要求。假设股票市场价格在每个时刻都在变化,您认为用户应该每时每刻刷新页面以告知最后价格吗?显然,对于这样的问题,这不是一个合理的解决方案。或者随着产品和服务的增加,我们需要客户服务来帮助用户和买家,最好和更便宜的沟通方式是通过聊天程序进行对话。出于同样的原因,我们不能强迫用户按下按钮来接收我们的上一条消息。

SignalR是一种实时技术,它使用异步库集在客户端和服务器之间建立持久连接。用户无需使用传统方式即可从服务器接收上次更新的数据,如刷新页面或按下按钮。

背景

您需要了解MVC 4.0技术和EntityFramework> 4.0才能更好地完成本文。

另一方面,SignalR使用以下方法建立实时网络:

1. WebSocket

Websocket是一种全双工协议,在内部使用http握手,允许消息流在TCP之上流动。它支持:Google Chrome> 16Fire Fox> 11IE> 10Win IIS> 8.0)。由于加密消息和全双工,websocket是最好的解决方案,并且首先signalR检查Web服务器和客户端服务器是否支持websocket

单工通讯

它只是以一种方式传播,当一个点只是广播而另一个点只能听而不发送信息,如电视和广播。

半双工

一个点发送消息,并且在这一瞬间的另一点无法发送消息,并且应该等待,直到第一点完成其传输,然后发送它的消息,它仅仅是一个每次一个通信线路,诸如旧无线设备对讲机和HTTP协议。

全双工

这两个点可以同时发送和接收消息,不需要等到其他点完成其传输,如电话和websocket协议。

全双工

2.服务器发送事件(SSE

signalr的下一个选择是服务器发送事件,因为服务器和客户端之间的持久性通信。在这种方法中,通信不会断开连接,服务器的最后数据将自动更新并通过HTTP连接传输到客户端。EventSourceHTML5技术的一部分。

var evsrc = new EventSource("url");// Load and Register Event Handler for Messages in this sectionevsrc.addEventListener("message", function (event) {//processing data in this section});

3.永远的Frame

当客户端向服务器发送请求时,服务器将一个隐藏的iframe作为chunked块发送给客户端,因此这个iframe负责永久保持客户端和服务器之间的连接。每当服务器更改数据,然后将数据作为脚本标记发送到客户端(隐藏的iframe),这些脚本将按顺序接收。

4.轮询

客户端立即向服务器发送请求和服务器响应发送请求,但在那之后,服务器再次断开连接以便在服务器和客户端之间建立通信,我们应该等待来自客户端的下一个请求。要解决此问题,我们必须手动设置超时,并且每10秒客户端向服务器发送请求以检查服务器端的新修改并获取上次更新数据。轮询使用资源,并且它不是经济的解决方案。

5.长轮询

客户端向服务器发送请求,服务器立即响应,此连接一直保持到特定时间,在此期间客户端不必向服务器发送显式请求,而在轮询中客户端必须在超时期间向服务器发送显式请求。Comet编程涵盖了这一概念。

简单的说,SignalR库在客户端和服务器之间选择一种传输数据的类型,其优先级是websocket,服务器发送事件,长轮询和永久iframe。该库中有两个类,如下所示:

1.持续连接

它是低级别的,因此它很复杂,需要更多的配置,但作为回报,它提供了更多的个人处理类的工具。

2. 集线器(Hub)

这是高水平,更受欢迎。

如何借助signalrhub类实现简单的聊天场景?

我的目的只是发出涉及signalr的随机场景。您可以将它用于您的个人场景,我只需按照以下步骤对服务器(集线器类)和客户端进行挑战,并说明客户端发送请求和服务器如何响应?他们如何互相交流?

场景描述

我想为客户服务部门建立一个应用程序。有些主管部门负责帮助客户,另一方面有客户提出问题并需要帮助。

假设两个管理员在线并连接到聊天服务,第一个客户端来问一个问题,所以系统连接第一个客户端到第一个免费管理员,第二个客户端这个过程会重复,但是第三个客户端从系统发出警报,没有管理员帮忙。每当第一个客户端断开连接时,第一个管理员就会自由。

我对这个场景的约定是使用标志来提醒连接的用户是用户还是管理员,以及哪个用户空闲或忙碌。在我的数据库中,如果admincode等于零,那么它是用户,否则它是管理员,我定义标志tpflag(在应用程序中)对于用户等于零,对于管理员等于1。每当他们连接到聊天标志时,freeflag变为零,这表示忙碌的用户,并且一旦客户端离开会话,就变成显示空闲状态的会话。

如果 freeflag == 0 ==>
如果freeflag == 1 ==>空闲
如果tpflag == 0 ==>用户
如果tpflag == 1 ==> 管理员

先决条件

  1. Visual Studio 2012
  2. SQL Server 2008
  3. 从包管理器控制台安装必要的依赖项

使用代码

1步:创建项目

文件 - >新项目 - > ASP.Net MVC 4 Web应用程序{提供名称和目录} - > {Template = BasicView Engine = Razor}

步骤2:打开PM以安装依赖项文件

菜单(工具) - >库包管理器 - >包管理器控制台

3步:删除旧依赖关系的指令

首先,删除所有旧版本,以便安装新版本的SignalR 2.xx In Line

PM>Uninstall-Package Microsoft.AspNet.SignalR –RemoveDependencies

4步:安装必要的依赖项文件的说明

对于新版本,请使用:

PM>Install-Package Microsoft.AspNet.SignalR

我已经使用signalr版本2.0.1进行此练习:

PM>Install-Package Microsoft.AspNet.SignalR -Version 2.0.1

PM>Install-Package Microsoft.Owin

通过编写该指令,nuget可以完成运行signalr所需的所有依赖注入。如果你看一下解决方案中的参考部分,你可以使用Microsoft.ASPNet.SignalR.xMicrosoft.Owin.xx等等,或者如果你看一下解决方案jquery-1.xjquery.signalR 2.xx等中的Scripts部分,那么对所有依赖感到安慰。

解决方案 - >打开引用 - >

解决方案 - >脚本 - >

另一方面,在成功安装signalR依赖项之后,您将在程序包控制台上方找到readme.txt完整帮助。它包含了开始使用signalr的所有必要指令。我将在接下来的步骤中解释这些说明。

提示(1):NuGet

如果您遇到此错误无法解析远程名称:'www.nuget.org'”那么您应该更改位于Package Source前面的Package Manager Settings

您应该将源从https更改为http协议以解决此问题。

提示(2):Owin

检查您的引用部分以确保有Owin,否则按照以下指示:右键单击引用 - >管理NuGet程序包 - >在左侧选择在线 - >搜索Owin - >选择OwinOwin IAppBuilder启动界面) - >安装。

然后你应该在你的引用部分看到Owin

5步:启动类

要在项目中启用signalr,您应该将类​​创建为启动类(startup)。(如果在以前版本的signalr中,我的意思是第一个版本,你曾经在global.asax中的Application Start中编写RouteTable.Routes.MapHubs();,现在忘记它并只使用启动类(startup)。右键单击:在项目名称上{SignalR} - >添加类 - - >名称:Startup.cs

using Microsoft.Owin;
using Owin;[assembly: OwinStartup(typeof(MvcSignal.Startup))]
namespace MvcSignal
{public class Startup{public void Configuration(IAppBuilder app){app.MapSignalR();}}
}

6步:根据我们的场景组织数据库

步骤6.1:创建“tbl_User”

tbl_user将收集用户和管理员,如果AdminCode由前一个表中的数字填充,那么它是属于department其他人的管理员,如果它被(零)填充说明给普通用户。{“UserID” int + identity=yes and “AdminCode” default value = 0}

步骤6.2:创建“tbl_Conversation”

tbl_Conversation将从用户和管理员之间的对话中收集数据。完成对话后将填写此表格。{“ConID”int + identity = yes}

7步:创建Hub

步骤7.1Model(文件夹) - >创建类“UserInfo.cs”

public class UserInfo{public string ConnectionId { get; set; }public string UserName { get; set; }public string UserGroup { get; set; }//if freeflag==0 ==> Busy//if freeflag==1 ==> Freepublic string freeflag { get; set; }//if tpflag==2 ==> User Admin//if tpflag==0 ==> User Member//if tpflag==1 ==> Adminpublic string tpflag { get; set; }public int UserID { get; set; }public int AdminID { get; set; } }

步骤7.2Model(文件夹) - >创建类“MessageInfo.cs”

public class MessageInfo{public string UserName { get; set; }public string Message { get; set; }public string UserGroup { get; set; }public string StartTime { get; set; }public string EndTime { get; set; }public string MsgDate { get; set; }}

步骤7.3Model(文件夹)?创建“HomeController.cs”

public ActionResult Chat(){ViewBag.Message = "Your contact page.";return View();}

右键单击Chat()- >选择添加视图 - >

步骤7.4:创建Chat.cshtml {Client Side}

@{ViewBag.Title = "Chat";
}<div id="divLogin" class="mylogin">User Name:<input id="txtUserName" type="text" /><br />Password :   <input id="txtPassword" type="password" /><br /><input id="btnLogin" type="button" value="Login" /><div id="divalarm"></div>
</div><div id="divChat" class="mylogin"><div id="welcome"></div><br />
<input id="txtMessage" type="text" />
<input id="btnSendMessage" type="button" value="Send" />
<div id="divMessage"></div></div><input id="hUserId" type="hidden" /><input id="hId" type="hidden" /><input id="hUserName" type="hidden" /><input id="hGroup" type="hidden" />@section scripts {<script src="~/Scripts/jquery-1.8.2.min.js"></script><script src="~/Scripts/jquery.signalR-2.0.1.min.js" type="text/javascript"></script><script src="~/signalr/hubs" type="text/javascript"></script>@*<script type="text/javascript" src="@Url.Content("~/signalr/hubs")"></script>*@@* <script type="text/javascript" src='<%= ResolveClientUrl("~/signalr/hubs") %>'></script>*@<script>$(function () { //This section will run whenever we call Chat.cshtml page$("#divChat").hide();$("#divLogin").show();var objHub = $.connection.myHub;loadClientMethods(objHub);$.connection.hub.start().done(function () {loadEvents(objHub);});});function loadEvents(objHub) {$("#btnLogin").click(function () {var name = $("#txtUserName").val();var pass = $("#txtPassword").val();if (name.length > 0 && pass.length > 0) {// <<<<<-- ***** Return to Server [  Connect  ] *****objHub.server.connect(name, pass);}else {alert("Please Insert UserName and Password");}});$('#btnSendMessage').click(function () {var msg = $("#txtMessage").val();if (msg.length > 0) {var userName = $('#hUserName').val();// <<<<<-- ***** Return to Server [  SendMessageToGroup  ] *****objHub.server.sendMessageToGroup(userName, msg);}});$("#txtPassword").keypress(function (e) {if (e.which == 13) {$("#btnLogin").click();}});$("#txtMessage").keypress(function (e) {if (e.which == 13) {$('#btnSendMessage').click();}});}function loadClientMethods(objHub) {objHub.client.NoExistAdmin = function () {var divNoExist = $('<div><p>There is no Admin to response you try again later</P></div>');$("#divChat").hide();$("#divLogin").show();$(divNoExist).hide();$('#divalarm').prepend(divNoExist);$(divNoExist).fadeIn(900).delay(9000).fadeOut(900);}objHub.client.getMessages = function (userName, message) {$("#txtMessage").val('');$('#divMessage').append('<div><p>' + userName + ': ' + message + '</p></div>');var height = $('#divMessage')[0].scrollHeight;$('#divMessage').scrollTop(height);}objHub.client.onConnected = function (id, userName, UserID, userGroup) {var strWelcome = 'Welcome' + +userName;$('#welcome').append('<div><p>Welcome:' + userName + '</p></div>');$('#hId').val(id);$('#hUserId').val(UserID);$('#hUserName').val(userName);$('#hGroup').val(userGroup);$("#divChat").show();$("#divLogin").hide();}}</script>
}

步骤7.5:创建Model1.edmx

为了有一个简单的方法从数据库中获取和插入数据,我按如下方式创建模型:右键单击项目名称 - >添加新项 - >选择“ADO.NET实体数据模型” - >选择生成从数据库“ - >连接到您的数据库 - >选择您的表格。

步骤8:创建文件夹并将其命名为Hubs然后创建简单类并将其命名为“MyHub.cs”

{如果您拥有Visual Studio的最新更新版本,则可以添加新项目并选择“SignalR Hub Class”}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.AspNet.SignalR;
using MvcSignal.Models;
using Microsoft.AspNet.SignalR.Hubs;namespace MvcSignal
{public class MyHub : Hub{static List UsersList = new List();static List<messageinfo> MessageList = new List<messageinfo>();//-->>>>> ***** Receive Request From Client [  Connect  ] *****public void Connect(string userName, string password){var id = Context.ConnectionId;string userGroup="";//Manage Hub Class//if freeflag==0 ==> Busy//if freeflag==1 ==> Free//if tpflag==0 ==> User//if tpflag==1 ==> Adminvar ctx = new TestEntities();var userInfo =(from m in ctx.tbl_Userwhere m.UserName == userName && m.Password == passwordselect new { m.UserID, m.UserName, m.AdminCode }).FirstOrDefault();try{//You can check if user or admin did not login before by below line which is an if condition//if (UsersList.Count(x => x.ConnectionId == id) == 0)//Here you check if there is no userGroup which is same DepID --> this is User otherwise this is Admin//userGroup = DepIDif ((int)userInfo.AdminCode == 0){//now we encounter ordinary user which needs userGroup and at this step, //system assigns the first of free Admin among UsersListvar strg = (from s in UsersList where (s.tpflag == "1") && (s.freeflag == "1") select s).First();userGroup = strg.UserGroup;//Admin becomes busy so we assign zero to freeflag which is shown admin is busystrg.freeflag = "0";//now add USER to UsersListUsersList.Add(new UserInfo { ConnectionId = id, UserID = userInfo.UserID, UserName = userName, UserGroup = userGroup, freeflag = "0", tpflag = "0", });//whether it is Admin or User now both of them has userGroup and I Join this user or admin to specific group Groups.Add(Context.ConnectionId, userGroup);Clients.Caller.onConnected(id, userName, userInfo.UserID, userGroup);}else{//If user has admin code so admin code is same userGroup//now add ADMIN to UsersListUsersList.Add(new UserInfo { ConnectionId = id, AdminID = userInfo.UserID, UserName = userName, UserGroup = userInfo.AdminCode.ToString(), freeflag = "1", tpflag = "1" });//whether it is Admin or User now both of them has userGroup and I Join this user or admin to specific group Groups.Add(Context.ConnectionId, userInfo.AdminCode.ToString());Clients.Caller.onConnected(id, userName, userInfo.UserID, userInfo.AdminCode.ToString());}                       }catch{string msg = "All Administrators are busy, please be patient and try again";//***** Return to Client *****Clients.Caller.NoExistAdmin();}}// <<<<<-- ***** Return to Client [  NoExist  ] *****//--group ***** Receive Request From Client [  SendMessageToGroup  ] *****public void SendMessageToGroup(string userName, string message){if (UsersList.Count != 0){var strg = (from s in UsersList where (s.UserName == userName) select s).First();MessageList.Add(new MessageInfo { UserName = userName, Message = message, UserGroup = strg.UserGroup });string strgroup = strg.UserGroup;// If you want to Broadcast message to all UsersList use below line// Clients.All.getMessages(userName, message);//If you want to establish peer to peer connection use below line //so message will be send just for user and admin who are in same group//***** Return to Client *****Clients.Group(strgroup).getMessages(userName, message);}}// <<<<<-- ***** Return to Client [  getMessages  ] *****//--group ***** Receive Request From Client ***** //{ Whenever User close session then OnDisconneced will be occurs }public override System.Threading.Tasks.Task OnDisconnected(){var item = UsersList.FirstOrDefault(x => x.ConnectionId == Context.ConnectionId);if (item != null){UsersList.Remove(item);var id = Context.ConnectionId;if (item.tpflag == "0"){//user logged off == usertry{var stradmin = (from s in UsersList where (s.UserGroup == item.UserGroup) && (s.tpflag == "1") select s).First();//become freestradmin.freeflag = "1";}catch{//***** Return to Client *****Clients.Caller.NoExistAdmin();}                    }//save conversation to dat abase}return base.OnDisconnected();}}
}</messageinfo>

规则和约定

客户端想要在服务器端调用服务器方法时的前缀:

(客户端 - >服务器)//客户端向服务器发送请求

1. objHub.server.methodname(){服务器端的方法名}

并且服务器端(myHub.cs类)中的方法名完全相同。

服务器想要在客户端调用客户端方法时的前缀:

(服务器 - >客户端)//服务器调用客户端方法&{客户端方法名称}

  1. Clients.caller.methodname() // caller表示只发送请求的用户
  2. Clients.all.methodname() // all表示所有已连接的用户
  3. Clients.Group(groupName).methodname() //Group仅表示同一组中的用户

当在MyHub.cs类中有*****返回客户端*****时,这意味着您必须在客户端编写具有相同名称的jquery函数。

确实,他们的互动如下:

提示(3):调用服务器类

每当你想要调用你的服务器类时,都有一些小技巧;总是在客户端你应该使用驼峰类型的特定命名约定,例如,如果你的集线器类名是MyHub,你应该从myHub实例化你的对象,或者如果你有SendMessageToGroup,你应该从sendMessageToGroup调用它,所以它应该是这样的:

测试用例

要获得相同的结果,您应该拥有与我在第七步中解释的数据库相同的数据库。

用例1

测试计划:如果客户端尝试登录且没有管理员,则系统会显示警报。

测试步骤

  1. 运行项目
  2. 用户名:mahsa
  3. 密码:123
  4. 预期输出:系统显示警报

用例2

测试计划:至少有空闲管理员,然后一个客户端登录,然后第一个管理员将分配给第一个需要帮助的空闲客户。

测试步骤

1. 运行项目

2. 用户名:admin1

3. 密码:123

4. 登录{admin1 as first admin}

5. 将URL复制到另一个Web浏览器

6. 用户名:mahsa

7. 密码:123

8. 登录{mahsa as first client}

9. 如果“mahsa”发送消息,那么“admin1”将看到它,因为它们在同一组中。当第一个客户端真正登录然后添加到第一个空闲管理员。

10. 将URL复制到另一个Web浏览器

11. 用户名:kashi

12. 密码:123

13. 登录{kashi as second client}

14. 系统显示警报并说没有管理员然后系统显示警报

15. 将URL复制到另一个Web浏览器

16. 用户名:admin2

17. 密码:123

18. “kashi”“admin2”无法看到“admin1”“mahsa”之间的对话

提示

提示1.管理员和用户的不同UI以及管理员的显示等待用户

如果您需要为User提供不同的用户界面,则应为用户和管理员创建不同的div,使用不同的css,并通过class属性为其分配特定的CSS

当您要从集线器类向Admin发送管理消息时,请发送到不同的客户端方法,例如objHub.client.getMessagesAdmin和用户objHub.client.getMessagesUser

Chat.cshtml中,通过不同的div“divMessageAdmin”“divMessageUser”使用不同的UI实现这些方法,您应该通过适当的消息填充这些div

所以请遵循:

1.创建不同的div

<div class="Admin" id="divMessageAdmin"></div>
<div Class="User" id="divMessageUser"></div>

2.Hub - > SendMessageToGroup - >

检查用户是否为Admin - >

Clients.Group(strgroup).getMessagesAdmin(userName, message);

检查用户是否是普通用户 - >

Clients.Group(strgroup).getMessagesUser(userName, message);

1.Chat.cshtml中:

如果用户是管理员:

objHub.client.getMessagesAdmin = function (userName, message) {$("#txtMessage").val('');$('#divMessageAdmin').append('<div><p>' + userName + ': ' + message + '</p></div>');var height = $('#divMessageAdmin')[0].scrollHeight;$('#divMessageAdmin').scrollTop(height);}

如果User是普通用户:

objHub.client.getMessagesUser = function(userName,message){ $('#getMessagesUser').append('<div><p>' + userName + ': ' + message + '</p></div>');var height = $('#getMessagesUser')[0].scrollHeight;$('#getMessagesUser').scrollTop(height);}

要在AdminUI中查看等待用户:

1.Hub类中 - >连接 - >你有这行代码

catch{string msg = "All Administrators are busy, please be patient and try again";// Return to Client Clients.Caller.NoExistAdmin();}

请为必须等待空闲管理员的用户发送用户名:

Clients.Caller.NoExistAdmin(username);

2.Chat.cshtml

objHub.client.NoExistAdmin = function (username) {var divNoExist = $('There is no Admin to response you try again later');             $("#divChat").hide(); $("#divLogin").show(); $("#divWaitingUser").append('' + userName + ''); $(divNoExist).hide(); $('#divalarm').prepend(divNoExist);     $(divNoExist).fadeIn(900).delay(9000).fadeOut(900);
}

原文地址:https://www.codeproject.com/Articles/732190/Real-Time-Web-Solution-for-Chat-by-MVC-SignalR-H

MVC SignalR Hub实时聊天实时Web解决方案相关推荐

  1. 微信小程序 -- 原生JS集成腾讯IM实时聊天/实时音视频(踩坑及心得)

    原生JS集成腾讯IM实时聊天/实时音视频对话功能 一.腾讯IM集成 前期准备 实例创建及初始化 IM登录 收发消息 二.腾讯音视频实时互动 跑通demo 三.同时集成即时通讯IM 和 音视频直播的 坑 ...

  2. C#——signalr实现简单的网页实时聊天

    1.新建asp.net web应用程序,然后在vs的NuGet包中下载安装Microsoft.AspNet.SignalR 2.右键项目->新建项,选择signalr集线器类,并写入代码,nam ...

  3. 用signalr实现简单的网页实时聊天

    开发工具与关键技术: js 作者:GuanLW 撰写时间:2022/3/18 第一步:先在vs的NuGet包中下载安装Microsoft.AspNet.SignalR.安装完成后会多以下几个文件 第二 ...

  4. 在Typescript中使用ASP.NET Core SignalR和React创建实时应用程序

    目录 介绍 ScrumPoker应用程序 源代码 开发工具 基本步骤 后端代码 创建Hub 在Startup中注册集线器 创建持久性 让我们为客户端应用程序公开一些终端 启用Cors 前端代码 结论 ...

  5. 使用声网的RTM SDK轻松给angular应用加上实时聊天功能

    作者:陈畏民 源起 今年寒假的前半段时间, 在家捣鼓了一个情侣类web应用, 基于aspnetcore和angular搭建的; 寒假中实现了'告白', '相册', '说说', '纪念日'这些功能, 然 ...

  6. 使用Pusher和Vue.js构建实时聊天应用

    如今,实时通信的应用程序越来越流畅,用户体验也变得越来越流行. 在本教程中,我们将使用由Chater提供的服务ChatKit提供支持的Vue.js构建实时聊天应用程序. ChatKit服务将为我们提供 ...

  7. websocket学习笔记 go语言使用 gorilla/websocket实现实时聊天项目

    完整代码:https://github.com/diguacheng/webchat 扩展包 gorilla/websocket的几个重要函数 协议升级 ,1)先初始化upgrader,再调用其upg ...

  8. Facebook,Twitter和实时聊天按钮:创建精通社交的WordPress网站

    博客是您的日常工作还是一次又一次的业余爱好都没关系. 无论您是刚刚成立初创公司并梦想着使其成为"一天"的梦想,还是您的企业目标严格以满足该财务季度的要求,社交媒体都是提高网站访问量 ...

  9. node mongoose_如何使用Express,Mongoose和Socket.io在Node.js中构建实时聊天应用程序

    node mongoose by Arun Mathew Kurian 通过阿伦·马修·库里安(Arun Mathew Kurian) 如何使用Express,Mongoose和Socket.io在N ...

最新文章

  1. IOS 实现滚动文字
  2. C#设置配置文件与读取配置文件
  3. 嵌入式与单片机之间的关系是什么?
  4. mysql导入source注意点
  5. Qt笔记-多线程检索数据库(单例多重锁,QtConcurrent::blockingMapped)
  6. 首发不同文件的md5碰撞真正方法——有图(视频教程加工具)非暴力碰撞!
  7. [Linux]常用命令与目录全拼
  8. 小程序 — 关于图片Base64转换及空间大小问题
  9. ai怎么做盒子效果图_ai怎么制作包装盒? Ai贴图工具制作包装盒的实例教程
  10. linux用户起名,如何在Linux中重命名用户(也可以重命名组和主目录)
  11. cnpm : 无法加载文件 C:\Users\AppData\Roaming\npm\cnpm.ps1,因为在此系统上禁止运行脚本。的解决方案之一
  12. java 基础数据结构_Java实现的基础数据结构
  13. AltiumDesigner之Logo制作
  14. Hbuilder X npx browserslist@latest --update-db
  15. s3c2410 2.6.22.1内核移植
  16. 2020香港公司开户的一些个人见解?香港银行开户免踩坑。
  17. An error occurred while installing package ‘conda-forge::certif‘ FileNotFoundError(2, ‘系统找不到指定的文件‘)
  18. 改变IDEA模板光标停留的位置
  19. 【偶爱宋词】章良能·小重山
  20. 最全面的微信小程序渲染图片的方式

热门文章

  1. 收获不止oracle在线,重温《收获不止Oracle》
  2. char添加一个字符_LINUX字符设备驱动模型分析(起始篇)
  3. 为什么你设计的网页不够惊艳?
  4. 高清壁纸|是时候换换心情了
  5. 智能贴图样机素材在手,海报逼格马上就有!
  6. UI设计素材干货模板|手机app夜间模式相关素材
  7. mysql exists依赖查询_MySQL EXISTS 和 NOT EXISTS 子查询
  8. QTableWidget插入项item方法 及误区
  9. arcengine二次开发 获取当前的坐标系统(C++)
  10. 4G终端-基站-核心网 信令流与数据流