Socket 由浅入深,开发一个真正的通信应用
在说socket之前。我们先了解下相关的网络知识;
端口
在Internet上有很多这样的主机,这些主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务(应用程序)。
例如:http 使用80端口 ftp使用21端口 smtp使用 25端口
端口用来标识计算机里的某个程序 1)公认端口:从0到1023 2)注册端口:从1024到49151 3)动态或私有端口:从49152到65535
Socket相关概念
socket的英文原义是“孔”或“插座”。作为进程通信机制,取后一种意思。通常也称作“套接字”,用于描述IP地址和端口,是一个通信链的句柄。(其实就是两个程序通信用的。)
socket非常类似于电话插座。以一个电话网为例。电话的通话双方相当于相互通信的2个程序,电话号码就是IP地址。任何用户在通话之前,
首先要占有一部电话机,相当于申请一个socket;同时要知道对方的号码,相当于对方有一个固定的socket。然后向对方拨号呼叫,
相当于发出连接请求。对方假如在场并空闲,拿起电话话筒,双方就可以正式通话,相当于连接成功。双方通话的过程,
是一方向电话机发出信号和对方从电话机接收信号的过程,相当于向socket发送数据和从socket接收数据。通话结束后,一方挂起电话机相当于关闭socket,撤消连接。
Socket有两种类型
流式Socket(STREAM):是一种面向连接的Socket,针对于面向连接的TCP服务应用,安全,但是效率低;
数据报式Socket(DATAGRAM):是一种无连接的Socket,对应于无连接的UDP服务应用.不安全(丢失,顺序混乱,在接收端要分析重排及要求重发),但效率高.
TCP/IP协议
TCP/IP(Transmission Control Protocol/Internet Protocol)即传输控制协议/网间协议,是一个工业标准的协议集,它是为广域网(WANs)设计的。
UDP协议
UDP(User Data Protocol,用户数据报协议)是与TCP相对应的协议。它是属于TCP/IP协议族中的一种。
应用层 (Application):应用层是个很广泛的概念,有一些基本相同的系统级 TCP/IP 应用以及应用协议,也有许多的企业商业应用和互联网应用。 解释:我们的应用程序
传输层 (Transport):传输层包括 UDP 和 TCP,UDP 几乎不对报文进行检查,而 TCP 提供传输保证。 解释;保证传输数据的正确性
网络层 (Network):网络层协议由一系列协议组成,包括 ICMP、IGMP、RIP、OSPF、IP(v4,v6) 等。 解释:保证找到目标对象,因为里面用的IP协议,ip包含一个ip地址
链路层 (Link):又称为物理数据网络接口层,负责报文传输。 解释:在物理层面上怎么去传递数据
你可以cmd打开命令窗口。输入
netstat -a
查看当前电脑监听的端口,和协议。有TCP和UDP
TCP/IP与UDP有什么区别呢?该怎么选择?
UDP可以用广播的方式。发送给每个连接的用户 而TCP是做不到的
TCP需要3次握手,每次都会发送数据包(但不是我们想要发送的数据),所以效率低 但数据是安全的。因为TCP会有一个校验和。就是在发送的时候。会把数据包和校验和一起 发送过去。当校验和和数据包不匹配则说明不安全(这个安全不是指数据会不会 别窃听,而是指数据的完整性)
UDP不需要3次握手。可以不发送校验和
web服务器用的是TCP协议
那什么时候用UDP协议。什么时候用TCP协议呢? 视频聊天用UDP。因为要保证速度?反之相反
下图显示了数据报文的格式
Socket一般应用模式(服务器端和客户端)
服务端跟客户端发送信息的时候,是通过一个应用程序 应用层发送给传输层,传输层加头部 在发送给网络层。在加头 在发送给链路层。在加帧
然后在链路层转为信号,通过ip找到电脑 链路层接收。去掉头(因为发送的时候加头了。去头是为了找到里面的数据) 网络层接收,去头 传输层接收。去头 在到应用程序,解析协议。把数据显示出来
TCP3次握手
在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认;SYN:同步序列编号(Synchronize SequenceNumbers)。 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
看一个Socket简单的通信图解
1.服务端welcoming socket 开始监听端口(负责监听客户端连接信息)
2.客户端client socket连接服务端指定端口(负责接收和发送服务端消息)
3.服务端welcoming socket 监听到客户端连接,创建connection socket。(负责和客户端通信)
服务器端的Socket(至少需要两个)
一个负责接收客户端连接请求(但不负责与客户端通信)
每成功接收到一个客户端的连接便在服务端产生一个对应的负责通信的Socket 在接收到客户端连接时创建. 为每个连接成功的客户端请求在服务端都创建一个对应的Socket(负责和客户端通信).
客户端的Socket
客户端Socket 必须指定要连接的服务端地址和端口。 通过创建一个Socket对象来初始化一个到服务器端的TCP连接。
Socket的通讯过程
服务器端:
申请一个socket 绑定到一个IP地址和一个端口上 开启侦听,等待接授连接
客户端: 申请一个socket 连接服务器(指明IP地址和端口号)
服务器端接到连接请求后,产生一个新的socket(端口大于1024)与客户端建立连接并进行通讯,原监听socket继续监听。
socket是一个很抽象的概念。来看看socket的位置
好吧。我承认看一系列的概念是非常痛苦的,现在开始编码咯
看来编码前还需要看下sokcet常用的方法
Socket方法: 1)IPAddress类:包含了一个IP地址 例:IPAddress ip = IPAddress.Parse(txtServer.Text);//将IP地址字符串转换后赋给ip 2) IPEndPoint类:包含了一对IP地址和端口号 例:IPEndPoint point = new IPEndPoint(ip, int.Parse(txtPort.Text));//将指定的IP地址和端口初始化后赋给point 3)Socket (): 创建一个Socket 例:Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建监听用的socket 4) Bind(): 绑定一个本地的IP和端口号(IPEndPoint) 例:socket.Bind(point);//绑定ip和端口 5) Listen(): 让Socket侦听传入的连接尝试,并指定侦听队列容量 例: socket.Listen(10); 6) Connect(): 初始化与另一个Socket的连接 7) Accept(): 接收连接并返回一个新的socket 例:Socket connSocket =socket .Accept (); 8 )Send(): 输出数据到Socket 9) Receive(): 从Socket中读取数据 10) Close(): 关闭Socket (销毁连接)
首先创建服务端,服务端是用来监听客户端请求的。
创建服务器步骤: 第一步:创建一个Socket,负责监听客户端的请求,此时会监听一个端口 第二步:客户端创建一个Socket去连接服务器的ip地址和端口号 第三步:当连接成功后。会创建一个新的socket。来负责和客户端通信
1 public static void startServer()
2 {
3
4 //第一步:创建监听用的socket
5 Socket socket = new Socket
6 (
7 AddressFamily.InterNetwork, //使用ip4
8 SocketType.Stream,//流式Socket,基于TCP
9 ProtocolType.Tcp //tcp协议
10 );
11
12 //第二步:监听的ip地址和端口号
13 //ip地址
14 IPAddress ip = IPAddress.Parse(_ip);
15 //ip地址和端口号
16 IPEndPoint point = new IPEndPoint(ip, _point);
17
18 //绑定ip和端口
19 //端口号不能占用:否则:以一种访问权限不允许的方式做了一个访问套接字的尝试
20 //通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
21 try
22 {
23 socket.Bind(point);
24 }
25 catch (Exception)
26 {
27
28 if (new IOException().InnerException is SocketException)
29 Console.WriteLine("端口被占用");
30 }
31 //socket.Bind(point);
32
33 //第三步:开始监听端口
34
35 //监听队列的长度
36 /*比如:同时有3个人来连接该服务器,因为socket同一个时间点。只能处理一个连接
37 * 所以其他的就要等待。当处理第一个。然后在处理第二个。以此类推
38 *
39 * 这里的10就是同一个时间点等待的队列长度为10,即。只能有10个人等待,当第11个的时候。是连接不上的
40 */
41 socket.Listen(10);
42
43 string msg = string.Format("服务器已经启动........\n监听ip为:{0}\n监听端口号为:{1}\n", _ip, _point);
44 showMsg(msg);
45
46 Thread listen = new Thread(Listen);
47 listen.IsBackground = true;
48 listen.Start(socket);
49
50 }
观察上面的代码。开启了一个多线程。去执行Listen方法,Listen是什么?为什么要开启一个多线程去执行?
回到上面的 "Socket的通讯过程"中提到的那个图片,因为有两个地方需要循环执行
第一个:需要循环监听来自客户端的请求
第二个:需要循环获取来自客服端的通信(这里假设是客户端跟服务器聊天)
额。这跟使用多线程有啥关系?当然有。因为Accept方法。会阻塞线程。所以用多线程,避免窗体假死。你说呢?
看看Listen方法
1 /// <summary>
2 /// 多线程执行
3 /// Accept方法。会阻塞线程。所以用多线程
4 /// </summary>
5 /// <param name="o"></param>
6 static void Listen(object o)
7 {
8 Socket socket = o as Socket;
9
10 //不停的接收来自客服端的连接
11 while (true)
12 {
13 //如果有客服端连接,则创建通信用是socket
14 //Accept方法。会阻塞线程。所以用多线程
15 //Accept方法会一直等待。直到有连接过来
16 Socket connSocket = socket.Accept();
17
18 //获取连接成功的客服端的ip地址和端口号
19 string msg = connSocket.RemoteEndPoint.ToString();
20 showMsg(msg + "连接");
21
22 //获取本机的ip地址和端口号
23 //connSocket.LocalEndPoint.ToString();
24
25 /*
26 如果不用多线程。则会一直执行ReceiveMsg
27 * 就不会接收客服端连接了
28 */
29 Thread th = new Thread(ReceiveMsg);
30 th.IsBackground = true;
31 th.Start(connSocket);
32
33 }
34 }
细心的你在Listen方法底部又看到了一个多线程。执行ReceiveMsg,对,没错。这就是上面说的。循环获取消息
ReceiveMsg方法定义:
1 /// <summary>
2 /// 接收数据
3 /// </summary>
4 /// <param name="o"></param>
5 static void ReceiveMsg(object o)
6 {
7 Socket connSocket = o as Socket;
8 while (true)
9 {
10
11 //接收数据
12 byte[] buffer = new byte[1024 * 1024];//1M
13 int num = 0;
14 try
15 {
16 //接收数据保存发送到buffer中
17 //num则为实际接收到的字节个数
18
19 //这里会遇到这个错误:远程主机强迫关闭了一个现有的连接。所以try一下
20 num = connSocket.Receive(buffer);
21 //当num=0.说明客服端已经断开
22 if (num == 0)
23 {
24 connSocket.Shutdown(SocketShutdown.Receive);
25 connSocket.Close();
26 break;
27 }
28 }
29 catch (Exception ex)
30 {
31 if (new IOException().InnerException is SocketException)
32 Console.WriteLine("网络中断");
33 else
34 Console.WriteLine(ex.Message);
35 break;
36 }
37
38 //把实际有效的字节转化成字符串
39 string str = Encoding.UTF8.GetString(buffer, 0, num);
40 showMsg(connSocket.RemoteEndPoint + "说:\n" + str);
41
42
43
44 }
45 }
提供服务器的完整代码如下:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Net.Sockets;
6 using System.Net;
7 using System.Threading;
8 using System.IO;
9 namespace CAServer
10 {
11 class Program
12 {
13
14 //当前主机ip
15 static string _ip = "192.168.1.2";
16 //端口号
17 static int _point = 8000;
18
19 static void Main(string[] args)
20 {
21 //Thread thread = new Thread(startServer);
22 //thread.Start();
23
24 startServer();
25
26 Console.ReadLine();
27
28 }
29
30 public static void startServer()
31 {
32
33 //第一步:创建监听用的socket
34 Socket socket = new Socket
35 (
36 AddressFamily.InterNetwork, //使用ip4
37 SocketType.Stream,//流式Socket,基于TCP
38 ProtocolType.Tcp //tcp协议
39 );
40
41 //第二步:监听的ip地址和端口号
42 //ip地址
43 IPAddress ip = IPAddress.Parse(_ip);
44 //ip地址和端口号
45 IPEndPoint point = new IPEndPoint(ip, _point);
46
47 //绑定ip和端口
48 //端口号不能占用:否则:以一种访问权限不允许的方式做了一个访问套接字的尝试
49 //通常每个套接字地址(协议/网络地址/端口)只允许使用一次。
50 try
51 {
52 socket.Bind(point);
53 }
54 catch (Exception)
55 {
56
57 if (new IOException().InnerException is SocketException)
58 Console.WriteLine("端口被占用");
59 }
60 //socket.Bind(point);
61
62 //第三步:开始监听端口
63
64 //监听队列的长度
65 /*比如:同时有3个人来连接该服务器,因为socket同一个时间点。只能处理一个连接
66 * 所以其他的就要等待。当处理第一个。然后在处理第二个。以此类推
67 *
68 * 这里的10就是同一个时间点等待的队列长度为10,即。只能有10个人等待,当第11个的时候。是连接不上的
69 */
70 socket.Listen(10);
71
72 string msg = string.Format("服务器已经启动........\n监听ip为:{0}\n监听端口号为:{1}\n", _ip, _point);
73 showMsg(msg);
74
75 Thread listen = new Thread(Listen);
76 listen.IsBackground = true;
77 listen.Start(socket);
78
79 }
80 /// <summary>
81 /// 多线程执行
82 /// Accept方法。会阻塞线程。所以用多线程
83 /// </summary>
84 /// <param name="o"></param>
85 static void Listen(object o)
86 {
87 Socket socket = o as Socket;
88
89 //不停的接收来自客服端的连接
90 while (true)
91 {
92 //如果有客服端连接,则创建通信用是socket
93 //Accept方法。会阻塞线程。所以用多线程
94 //Accept方法会一直等待。直到有连接过来
95 Socket connSocket = socket.Accept();
96
97 //获取连接成功的客服端的ip地址和端口号
98 string msg = connSocket.RemoteEndPoint.ToString();
99 showMsg(msg + "连接");
100
101 //获取本机的ip地址和端口号
102 //connSocket.LocalEndPoint.ToString();
103
104 /*
105 如果不用多线程。则会一直执行ReceiveMsg
106 * 就不会接收客服端连接了
107 */
108 Thread th = new Thread(ReceiveMsg);
109 th.IsBackground = true;
110 th.Start(connSocket);
111
112 }
113 }
114 /// <summary>
115 /// 接收数据
116 /// </summary>
117 /// <param name="o"></param>
118 static void ReceiveMsg(object o)
119 {
120 Socket connSocket = o as Socket;
121 while (true)
122 {
123
124 //接收数据
125 byte[] buffer = new byte[1024 * 1024];//1M
126 int num = 0;
127 try
128 {
129 //接收数据保存发送到buffer中
130 //num则为实际接收到的字节个数
131
132 //这里会遇到这个错误:远程主机强迫关闭了一个现有的连接。所以try一下
133 num = connSocket.Receive(buffer);
134 //当num=0.说明客服端已经断开
135 if (num == 0)
136 {
137 connSocket.Shutdown(SocketShutdown.Receive);
138 connSocket.Close();
139 break;
140 }
141 }
142 catch (Exception ex)
143 {
144 if (new IOException().InnerException is SocketException)
145 Console.WriteLine("网络中断");
146 else
147 Console.WriteLine(ex.Message);
148 break;
149 }
150
151 //把实际有效的字节转化成字符串
152 string str = Encoding.UTF8.GetString(buffer, 0, num);
153 showMsg(connSocket.RemoteEndPoint + "说:\n" + str);
154
155
156
157 }
158 }
159 /// <summary>
160 /// 显示消息
161 /// </summary>
162 static void showMsg(string msg)
163 {
164 Console.WriteLine(msg);
165 //Console.ReadKey();
166 }
167 }
168 }
运行代码。显示如下
是不是迫不及待的想试试看效果。好吧其实我也跟你一样,cmd打开dos命令提示符,输入
telnet 192.168.1.2 8000
回车,会看到窗体名称变了
然后看到服务器窗口
然后在客户端输入数字试试
我输入了1 2 3 。当然,在cmd窗口是不显示的。这不影响测试。
小技巧:为了便于测试,可以创建一个xx.bat文件。里面写命令
telnet 192.168.1.2 8000
这样只有每次打开就会自动连接了。
当然。这仅仅是测试。现在写一个客户端,
创建一个winfrom程序,布局如下显示
请求服务器代码就很容易了。直接附上代码
1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel;
4 using System.Data;
5 using System.Drawing;
6 using System.Linq;
7 using System.Text;
8 using System.Windows.Forms;
9 using System.Net;
10 using System.Net.Sockets;
11
12 namespace WFAClient
13 {
14 public partial class Form1 : Form
15 {
16 public Form1()
17 {
18 InitializeComponent();
19 }
20 Socket socket;
21 private void btnOk_Click(object sender, EventArgs e)
22 {
23 //客户端连接IP
24 IPAddress ip = IPAddress.Parse(tbIp.Text);
25
26 //端口号
27 IPEndPoint point = new IPEndPoint(ip, int.Parse(tbPoint.Text));
28
29 socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
30
31 try
32 {
33 socket.Connect(point);
34 msg("连接成功");
35 btnOk.Enabled = false;
36 }
37 catch (Exception ex)
38 {
39 msg(ex.Message);
40 }
41 }
42 private void msg(string msg)
43 {
44 tbMsg.AppendText(msg);
45
46 }
47
48 private void btnSender_Click(object sender, EventArgs e)
49 {
50 //发送信息
51 if (socket != null)
52 {
53 byte[] buffer = Encoding.UTF8.GetBytes(tbContent.Text);
54 socket.Send(buffer);
55 /*
56 * 如果不释放资源。当关闭连接的时候
57 * 服务端接收消息会报如下异常:
58 * 远程主机强迫关闭了一个现有的连接。
59 */
60 //socket.Close();
61 //socket.Disconnect(true);
62 }
63 }
64 }
65 }
运行测试,这里需要同时运行客户端和服务器,
首先运行服务器,那怎么运行客户端呢。
右键客户端项目。调试--》启用新实例
好了。一个入门的过程就这样悄悄的完成了。
以上内容来自:http://www.cnblogs.com/nsky/p/4501782.html
根据上面的内容,已经可以开发出一个可以正常通信的Socket示例了,
接下来首先要考虑的就是服务器性能问题
1)在服务器接收数据的时候,定义了一个1M的Byte Buffer,有些设计的更大。更大Buffer可以保证客户端发送数据量很大的情况全部能接受完全。但是作为一个服务器每收到一条客户端请求,都要申请一个1M的Buffer去装客户端发送的数据。如果客户端的并发量很大的情况,还没等到网络的瓶颈,服务器内存开销已经吃不消了。
对于这个问题的解决思路是:
定义一个小Buffer,每次接受客户端请求用:
byte[] bufferTemp = new byte[1024];
和一个大Buffer,装客户端的所有数据,其中用到了strReceiveLength,是客户端发送的总长度,稍后再解释:
byte[] buffer = new byte[Convert.ToInt32(strReceiveLength)];
改写while (true)循环,每次接受1K的数据,然后用Array.Copy方法,把bufferTemp中的数据复制给buffer:
num = connSocket.Receive(bufferTemp, SocketFlags.None);
ArrayUtil.ArrayCopy(bufferTemp, buffer, check, num);
check += num;
这个Array.Copy是重点,因为TCP数据流在传输过程中也是一个包一个包的传送,最大不超过8K。所以每次接受到的数据,也就是bufferTemp这个变量有可能装满,也有可能装不满。所以在拷贝的时候一定按照这次接受的长度顺序的放入buffer中。等到客户端全部数据发送完成后,再把buffer转换:
strReceive = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
而不能够每次都转换,再strReceive += 一个Byte数组。这样做的后果就是中文会被截断,因为中文在UTF-8编码下占3-4个字节,很容易出现乱码。
2)数据长度校验
TCP在传输过程中难免会有数据发送不全或者丢失的情况。所以在客户端发送数据的时候一定带上校验长度:
byte[] btyLength = Encoding.UTF8.GetBytes(strContent);
string strLength = btyLength.Length.ToString().PadLeft(8, '0');
string sendData = strLength + strContent;
byte[] buffer = Encoding.UTF8.GetBytes(sendData);
socketClient.Send(buffer);
这样在服务器端,先把要接受的长度收到:
byte[] bufferLength = new byte[8];
num = connSocket.Receive(bufferLength);
strReceiveLength = Encoding.UTF8.GetString(bufferLength, 0, bufferLength.Length);
在循环里用下面的判断,来校验和判断是否已经接受完毕:
if (check == Convert.ToInt32(strReceiveLength))
3)设计上一些方式
很多局域网的部署是分层的,也就是分内网和外网。服务器部署一定要在外网上部署,这里的外网指的是在客户端之上的网段上。
比如192.168.1.22下有个无线路由,无线连接的IP段为192.168.2.1~254
服务器搭建在192.168.1网段下,192.168.2的客户端是可以访问的。但是相反则不行,192.168.1网段下的设备无法主动找到192.168.2的服务器。
Socket 由浅入深,开发一个真正的通信应用的更多相关文章
- 与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室
原文:与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
- 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室
原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
- 使用React、Node.js、MongoDB、Socket.IO开发一个角色投票应用的学习过程(三)
这几篇都是我原来首发在 segmentfault 上的地址:https://segmentfault.com/a/1190000005040834 突然想起来我这个博客冷落了好多年了,也该更新一下,呵 ...
- python socket编程---从使用Python开发一个Socket示例说到开发者的思维和习惯问题
今天主要说的是一个开发者的思维和习惯问题. 思维包括编程的思维和解决一个具体问题的分析思维,分析思路,分析方法,甚至是分析工具. 无论是好习惯还是不好的习惯,都是在者一天一天的思维中形成的.那些不好的 ...
- 如何在嵌入式Linux上开发一个语音通信解决方案
开发一个语音通信解决方案是一个软件项目.既然是软件项目,就要有相应的计划:有多少功能,安排多少软件工程师去做,这些工程师在这一领域的经验如何,是否需要培训,要多长时间做完,中间有几个主要的milest ...
- Python之路,Day18 - 开发一个WEB聊天来撩妹吧
Python之路,Day18 - 开发一个WEB聊天来撩妹吧 本节内容: 项目实战:开发一个WEB聊天室 功能需求: 用户可以与好友一对一聊天 可以搜索.添加某人为好友 用户可以搜索和添加群 每个 ...
- python 开发一个支持多用户在线的FTP
### 作者介绍:* author:lzl### 博客地址:* http://www.cnblogs.com/lianzhilei/p/5813986.html### 功能实现 作业:开发一个支持多用 ...
- Socket 由浅入深系列--------- 简单实现编程(三)
socket 由浅入深 原理(一)介绍了一些,以下也就是简单实现,并未考虑其它性能化! 使用TCP的server客户机举例 server 设置一个简单的TCPserver涉及下列步骤: 调用 sock ...
- 基于线程开发一个FTP服务器
一,项目题目:基于线程开发一个FTP服务器 二,项目要求: 基本要求: 1.用户加密认证 2.允许同时多用户登录 3.每个用户有自己的家目录 ,且只能访问自己的家目录 4.对用户进行磁盘配 ...
随机推荐
- Hangfire实战二——为DashBoard页面添加权限认证
概述 Hangfire Dashboard为我们提供了可视化的对后台任务进行管理的界面,我们可以直接在这个页面上对定时任务进行删除.立即执行等操作,如下图所示: 默认情况下,这个页面只能在部署Hang ...
- Jsonp处理跨域请求
Jsonp的使用需要前端和后端共同配合来完成 服务端设置(ASP.NET MVC实现): 在将返回的Json数据包在一个方法名称的内部,如上 客户端设置: 同时要加上一个回调函数用于处理请求的数据 在 ...
- js 自定义阻止事件冒泡函数
// 以下改方法全兼容Chrome function stopBubble(event){ if(event.stopPropagation){ // 兼容火狐(firebox) event.st ...
- 帮助你更好的理解Spring循环依赖
网上关于Spring循环依赖的博客太多了,有很多都分析的很深入,写的很用心,甚至还画了时序图.流程图帮助读者理解,我看了后,感觉自己是懂了,但是闭上眼睛,总觉得还没有完全理解,总觉得还有一两个坎过不去 ...
- 设计模式:state模式
核心: 把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化 例子: class State //状态接口 { public: virtual void show() = 0; ...
- layui 数据表格自带的导出Excel,身份证等E+/000问题解决
layui数据表格的工具栏自带导出Excel 会将身份证等 长整数的 自动变成E+并且 后面有000.从而导致数据不能完整导出. 解决方案: 1.先下载Excel的插件包.将压缩包内的两个js放到 l ...
- OFDM通信系统的MATLAB仿真(1)
由于是第一篇博客,想先说点废话,其实自己早就想把学到的一些东西总结成文章随笔之类的供自己复习时查看的了.但是一是觉得自己学的的不够深入,总结也写不出什么很深刻的东西:二是觉得网上也有海量的资料了,需要 ...
- 轻量级分布式延时任务处理组件easyTask-L-入门篇
今天给大家介绍一款新武器.我自研的一个java组件easyTask-L.这个是做啥的呢?我之前研发了一款单机版本的easyTask,这次是要介绍另外一款easyTask-L.区别就是后者支持分布式环境 ...
- Unity 基于excel2json批处理读取Excel表并反序列化
excel2json是一款将Excel表格文件快速生成json和C#数据类的高效插件,详情了解如下: https://neil3d.github.io/coding/excel2json.html 该 ...
- web自动化 -- 消息提示框处理 (alert、confirm、prompt)
一.前提知识 1.警告消息框(alert) 警告消息框提供了一个"确定"按钮让用户关闭该消息框,并且该消息框是模式对话框,也就是说用户必须先关闭该消息框然后才能继续进行操作. 2. ...