当前位置: 首页 > 编程日记 > 正文

C# Socket系列三 socket通信的封包和拆包

通过系列二 我们已经实现了socket的简单通信 接下来我们测试一下,在时间应用的场景下,我们会快速且大量的传输数据的情况!

 1    class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             TCPListener tcp = new TCPListener();
 6             TSocketClient client = new TSocketClient();
 7             for (int i = 0; i < 10; i++)
 8             {
 9                 client.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Server!"));
10             }
11             Console.ReadLine();
12         }
13     }

我们通过测试代码快速发送10条消息到服务器去,

我们看看运行结果

这样不难看出,我们的客户端发送了10条消息,但是服务器收到的时候变成了两条消息,回复客户端自然就变成两次回复。

这是为什么呢?

我们修改一下程序一秒钟发送一次消息试试

 1    class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             TCPListener tcp = new TCPListener();
 6             TSocketClient client = new TSocketClient();
 7             for (int i = 0; i < 5; i++)
 8             {
 9                 Thread.Sleep(1000);
10                 client.SendMsg(System.Text.UTF8Encoding.Default.GetBytes("Holle Server!"));
11             }
12             Console.ReadLine();
13         }
14     }

运行看看,

这次对了那么分析分析到底为什么呢?
这是socket的底层,做的手脚。因为我设置socket的发送和接受缓冲区
//10K的缓冲区空间 private int BufferSize = 10 * 1024; 10k的缓冲区,
且socket的底层 发送消息会有一定间隙,虽然这个时间很短,但是我们直接for循环发送的话,时间同意很快,
因为socket.send()方法并非真实的发送数据而是把数据压入发送缓冲区。
那么我们就明白了为什么会出现上面的情况
出现了这样的情况我们要怎么解决呢?
时间应用场景不可能1秒钟才一条消息啥。
我们知道了导致这个问题的原因是因为消息发送是出现了快速压入很多发送消息到待发送缓冲区里面一起发送导致的。这样情况就是粘包了,那么我们是不是可以考虑给每一个消息加入包标识呢?

接下来我们修改一下发送包的数据代码

创建消息的构造体 TSocketMessage

 1  /// <summary>
 2     /// 底层通信消息
 3     /// </summary>
 4     public class TSocketMessage : IDisposable
 5     {
 6         /// <summary>
 7         /// 消息ID
 8         /// </summary>
 9         public int MsgID;
10         /// <summary>
11         /// 消息内容
12         /// </summary>
13         public byte[] MsgBuffer;
14 
15         public TSocketMessage(int msgID, byte[] msg)
16         {
17             this.MsgID = msgID;
18             this.MsgBuffer = msg;
19         }
20 
21         public void Dispose()
22         {
23             this.Dispose(true);
24             GC.SuppressFinalize(this);
25         }
26 
27         protected virtual void Dispose(bool flag1)
28         {
29             if (flag1) { this.MsgBuffer = null; }
30         }
31     }

接下来我们创建消息包的封装和拆分 MarshalEndian

  1  public class MarshalEndian
  2     {
  3         //用于存储剩余未解析的字节数
  4         private List<byte> _LBuff = new List<byte>(2);
  5         //默认是utf8的编码格式
  6         private UTF8Encoding utf8 = new UTF8Encoding();
  7 
  8         //包头1
  9         const Int16 t1 = 0x55;
 10         //包头2
 11         const Int16 t2 = 0xAA;
 12         //字节数常量 两个包头4个字节,一个消息id4个字节,封装消息长度 long 8个字节
 13         const long ConstLenght = 12L;
 14 
 15         public void Dispose()
 16         {
 17             this.Dispose(true);
 18             GC.SuppressFinalize(this);
 19         }
 20 
 21         protected virtual void Dispose(bool flag1)
 22         {
 23             if (flag1)
 24             {
 25                 IDisposable disposable2 = this.utf8 as IDisposable;
 26                 if (disposable2 != null) { disposable2.Dispose(); }
 27                 IDisposable disposable = this._LBuff as IDisposable;
 28                 if (disposable != null) { disposable.Dispose(); }
 29             }
 30         }
 31 
 32         public byte[] Encode(TSocketMessage msg)
 33         {
 34             MemoryStream ms = new MemoryStream();
 35             BinaryWriter bw = new BinaryWriter(ms, new UTF8Encoding());
 36             byte[] msgBuffer = msg.MsgBuffer;
 37 
 38             #region 封装包头
 39             bw.Write((Int16)t1);
 40             bw.Write((Int16)t2);
 41             #endregion
 42 
 43             #region 包协议
 44             if (msgBuffer != null)
 45             {
 46                 bw.Write((Int64)(msgBuffer.Length + 4));
 47                 bw.Write(msg.MsgID);
 48                 bw.Write(msgBuffer);
 49             }
 50             else { bw.Write((Int64)0); }
 51             #endregion
 52 
 53             bw.Close();
 54             ms.Close();
 55             bw.Dispose();
 56             ms.Dispose();
 57             return ms.ToArray();
 58         }
 59 
 60         public List<TSocketMessage> GetDcAppMess(byte[] buff, int len)
 61         {
 62             //拷贝本次的有效字节
 63             byte[] _b = new byte[len];
 64             Array.Copy(buff, 0, _b, 0, _b.Length);
 65             buff = _b;
 66             if (this._LBuff.Count > 0)
 67             {
 68                 //拷贝之前遗留的字节
 69                 this._LBuff.AddRange(_b);
 70                 buff = this._LBuff.ToArray();
 71                 this._LBuff.Clear();
 72                 this._LBuff = new List<byte>(2);
 73             }
 74 
 75             List<TSocketMessage> list = new List<TSocketMessage>();
 76             MemoryStream ms = new MemoryStream(buff);
 77             BinaryReader buffers = new BinaryReader(ms, this.utf8);
 78             try
 79             {
 80                 byte[] _buff;
 81             Label_0073:
 82                 //判断本次解析的字节是否满足常量字节数 
 83                 if ((buffers.BaseStream.Length - buffers.BaseStream.Position) < ConstLenght)
 84                 {
 85                     _buff = new byte[(int)(buffers.BaseStream.Length - buffers.BaseStream.Position)];
 86                     Array.Copy(buff, (int)buffers.BaseStream.Position, _buff, 0, _buff.Length);
 87                     this._LBuff.AddRange(_buff);
 88                     return list;
 89                 }
 90                 #region 包头读取
 91             //循环读取包头
 92             Label_00983:
 93                 Int16 tt1 = buffers.ReadInt16();
 94                 Int16 tt2 = buffers.ReadInt16();
 95                 if (!(tt1 == t1 && tt2 == t2))
 96                 {
 97                     long ttttt = buffers.BaseStream.Seek(-3, SeekOrigin.Current);
 98                     goto Label_00983;
 99                 }
100                 #endregion
101 
102                 #region 包协议
103                 long offset = buffers.ReadInt64();
104                 #endregion
105 
106                 #region 包解析
107                 //剩余字节数大于本次需要读取的字节数
108                 if (offset < (buffers.BaseStream.Length - buffers.BaseStream.Position))
109                 {
110                     int msgID = buffers.ReadInt32();
111                     _buff = new byte[offset - 4];
112                     Array.Copy(buff, (int)buffers.BaseStream.Position, _buff, 0, _buff.Length);
113                     list.Add(new TSocketMessage(msgID, _buff));
114                     //设置偏移量 然后继续循环读取
115                     buffers.BaseStream.Seek(offset, SeekOrigin.Current);
116                     goto Label_0073;
117                 }
118                 else if (offset == (buffers.BaseStream.Length - buffers.BaseStream.Position))
119                 {
120                     int msgID = buffers.ReadInt32();
121                     //剩余字节数刚好等于本次读取的字节数
122                     _buff = new byte[offset - 4];
123                     Array.Copy(buff, (int)buffers.BaseStream.Position, _buff, 0, _buff.Length);
124                     list.Add(new TSocketMessage(msgID, _buff));
125                 }
126                 else
127                 {
128                     //剩余字节数刚好小于本次读取的字节数 存起来,等待接受剩余字节数一起解析
129                     _buff = new byte[(int)(buffers.BaseStream.Length - buffers.BaseStream.Position + ConstLenght)];
130                     Array.Copy(buff, (int)(buffers.BaseStream.Position - ConstLenght), _buff, 0, _buff.Length);
131                     buff = _buff;
132                     this._LBuff.AddRange(_buff);
133                 }
134                 #endregion
135 
136             }
137             catch { }
138             finally
139             {
140                 if (buffers != null) { buffers.Dispose(); }
141                 buffers.Close();
142                 if (buffers != null) { buffers.Dispose(); }
143                 ms.Close();
144                 if (ms != null) { ms.Dispose(); }
145             }
146             return list;
147         }
148     }

接下来我们修改一下 TSocketBase 的 抽象方法

1  public abstract void Receive(TSocketMessage msg);

在修改接受消息回调函数

 1   /// <summary>
 2         /// 消息解析器
 3         /// </summary>
 4         MarshalEndian mersha = new MarshalEndian();
 5 
 6         /// <summary>
 7         /// 接收消息回调函数
 8         /// </summary>
 9         /// <param name="iar"></param>
10         private void ReceiveCallback(IAsyncResult iar)
11         {
12             if (!this.IsDispose)
13             {
14                 try
15                 {
16                     //接受消息
17                     ReceiveSize = _Socket.EndReceive(iar, out ReceiveError);
18                     //检查状态码
19                     if (!CheckSocketError(ReceiveError) && SocketError.Success == ReceiveError)
20                     {
21                         //判断接受的字节数
22                         if (ReceiveSize > 0)
23                         {
24                             byte[] rbuff = new byte[ReceiveSize];
25                             Array.Copy(this.Buffers, rbuff, ReceiveSize);
26                             var msgs = mersha.GetDcAppMess(rbuff, ReceiveSize);
27                             foreach (var msg in msgs)
28                             {
29                                 this.Receive(msg);
30                             }
31                             //重置连续收到空字节数
32                             ZeroCount = 0;
33                             //继续开始异步接受消息
34                             ReceiveAsync();
35                         }
36                         else
37                         {
38                             ZeroCount++;
39                             if (ZeroCount == 5) { this.Close("错误链接"); }
40                         }
41                     }
42                 }
43                 catch (System.Net.Sockets.SocketException) { this.Close("链接已经被关闭"); }
44                 catch (System.ObjectDisposedException) { this.Close("链接已经被关闭"); }
45             }
46         }

这样我们完成了在收到消息后对数据包的解析。

修改一下TSocketClient的 Receive 重写方法

 1         /// <summary>
 2         /// 收到消息后
 3         /// </summary>
 4         /// <param name="rbuff"></param>
 5         public override void Receive(TSocketMessage msg)
 6         {
 7             Console.WriteLine("Receive ID:" + msg.MsgID + " Msg:" + System.Text.UTF8Encoding.Default.GetString(msg.MsgBuffer));
 8             if (isServer)
 9             {
10                 this.SendMsg(new TSocketMessage(msg.MsgID, System.Text.UTF8Encoding.Default.GetBytes("Holle Client!")));
11             }
12         }

修改测试代码如下

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             TCPListener tcp = new TCPListener();
 6             TSocketClient client = new TSocketClient();
 7             for (int i = 1; i < 5; i++)
 8             {
 9                 Thread.Sleep(1000);
10                 client.SendMsg(new TSocketMessage(i, System.Text.UTF8Encoding.Default.GetBytes("Holle Server!")));
11             }
12             Console.ReadLine();
13         }
14     }

运行结果

接受成功了,那么我们取消暂停状态,快速发送消息试试

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             TCPListener tcp = new TCPListener();
 6             TSocketClient client = new TSocketClient();
 7             for (int i = 1; i < 5; i++)
 8             {
 9                 client.SendMsg(new TSocketMessage(i, System.Text.UTF8Encoding.Default.GetBytes("Holle Server!")));
10             }
11             Console.ReadLine();
12         }
13     }

看看运行结果

瞬间完成了消息发送,也没有再出现第一次运行的那样~!

这样完美的解决了socket通信 在传输上发送粘包问题

下载程序完整代码

谢谢园友发现的问题,

问题是这样的原本的解包和封包的测试代码不够严谨导致解析包出现错误
感谢园友发现问题,并提出问题。

附上最新的代码

  1 using System;
  2 using System.Collections.Generic;
  3 using System.IO;
  4 using System.Linq;
  5 using System.Text;
  6 using System.Threading.Tasks;
  7 
  8 namespace TSocket
  9 {
 10     public class MarshalEndian
 11     {
 12         //用于存储剩余未解析的字节数
 13         private List<byte> _LBuff = new List<byte>(2);
 14         //默认是utf8的编码格式
 15         private UTF8Encoding utf8 = new UTF8Encoding();
 16 
 17         //包头1
 18         const Int16 t1 = 0x55;
 19         //包头2
 20         const Int16 t2 = 0xAA;
 21         //字节数常量 两个包头4个字节,一个消息id4个字节,封装消息长度 int32 4个字节
 22         const Int32 ConstLenght = 8;
 23 
 24         public void Dispose()
 25         {
 26             this.Dispose(true);
 27             GC.SuppressFinalize(this);
 28         }
 29 
 30         protected virtual void Dispose(bool flag1)
 31         {
 32             if (flag1)
 33             {
 34                 IDisposable disposable2 = this.utf8 as IDisposable;
 35                 if (disposable2 != null) { disposable2.Dispose(); }
 36                 IDisposable disposable = this._LBuff as IDisposable;
 37                 if (disposable != null) { disposable.Dispose(); }
 38             }
 39         }
 40 
 41         public byte[] Encode(TSocketMessage msg)
 42         {
 43             MemoryStream ms = new MemoryStream();
 44             BinaryWriter bw = new BinaryWriter(ms, new UTF8Encoding());
 45             byte[] msgBuffer = msg.MsgBuffer;
 46 
 47             #region 封装包头
 48             bw.Write((Int16)t1);
 49             bw.Write((Int16)t2);
 50             #endregion
 51 
 52             #region 包协议
 53             if (msgBuffer != null)
 54             {
 55                 bw.Write((Int32)(msgBuffer.Length + 4));
 56                 bw.Write(msg.MsgID);
 57                 bw.Write(msgBuffer);
 58             }
 59             else { bw.Write((Int32)0); }
 60             #endregion
 61 
 62             bw.Close();
 63             ms.Close();
 64             bw.Dispose();
 65             ms.Dispose();
 66             return ms.ToArray();
 67         }
 68 
 69         public List<TSocketMessage> GetDcAppMess(byte[] buff, int len)
 70         {
 71             //拷贝本次的有效字节
 72             byte[] _b = new byte[len];
 73             Array.Copy(buff, 0, _b, 0, _b.Length);
 74             buff = _b;
 75             if (this._LBuff.Count > 0)
 76             {
 77                 //拷贝之前遗留的字节
 78                 this._LBuff.AddRange(_b);
 79                 buff = this._LBuff.ToArray();
 80                 this._LBuff.Clear();
 81                 this._LBuff = new List<byte>(2);
 82             }
 83 
 84             List<TSocketMessage> list = new List<TSocketMessage>();
 85             MemoryStream ms = new MemoryStream(buff);
 86             BinaryReader buffers = new BinaryReader(ms, this.utf8);
 87             try
 88             {
 89                 byte[] _buff;
 90             Label_00983:
 91 
 92                 #region 包头读取
 93                 //循环读取包头           
 94                 //判断本次解析的字节是否满足常量字节数 
 95                 if ((buffers.BaseStream.Length - buffers.BaseStream.Position) < ConstLenght)
 96                 {
 97                     _buff = buffers.ReadBytes((int)(buffers.BaseStream.Length - buffers.BaseStream.Position));
 98                     this._LBuff.AddRange(_buff);
 99                     return list;
100                 }
101                 Int16 tt1 = buffers.ReadInt16();
102                 Int16 tt2 = buffers.ReadInt16();
103                 if (!(tt1 == t1 && tt2 == t2))
104                 {
105                     long ttttt = buffers.BaseStream.Seek(-3, SeekOrigin.Current);
106                     goto Label_00983;
107                 }
108                 #endregion
109 
110                 #region 包协议
111                 int offset = buffers.ReadInt32();
112                 #endregion
113 
114                 #region 包解析
115                 //剩余字节数大于本次需要读取的字节数
116                 if (offset <= (buffers.BaseStream.Length - buffers.BaseStream.Position))
117                 {
118                     int msgID = buffers.ReadInt32();
119                     _buff = buffers.ReadBytes(offset - 4);
120                     list.Add(new TSocketMessage(msgID, _buff));
121                     if ((buffers.BaseStream.Length - buffers.BaseStream.Position) > 0)
122                     {
123                         goto Label_00983;
124                     }
125                 }
126                 else
127                 {
128                     //剩余字节数刚好小于本次读取的字节数 存起来,等待接受剩余字节数一起解析
129                     _buff = buffers.ReadBytes((int)(buffers.BaseStream.Length - buffers.BaseStream.Position + ConstLenght));
130                     this._LBuff.AddRange(_buff);
131                 }
132                 #endregion
133             }
134             catch (Exception ex) { Console.WriteLine(ex); }
135             finally
136             {
137                 if (buffers != null) { buffers.Dispose(); }
138                 buffers.Close();
139                 if (buffers != null) { buffers.Dispose(); }
140                 ms.Close();
141                 if (ms != null) { ms.Dispose(); }
142             }
143             return list;
144         }
145     }
146 }

转载于:https://www.cnblogs.com/shizuchengxuyuan/p/4344868.html

相关文章:

Java项目:CRM客户管理系统(java+SSM+jsp+mysql+maven)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能包括&#xff1a; 用户管理&#xff0c;系统管理&#xff0c;客户管理&#xff0c;客户服务&#xff0c;客户关怀, 销售机会&#xff0c;统计管理等等。 二、项目运行 环境配置&#x…

Android 获取标题栏的高度

2019独角兽企业重金招聘Python工程师标准>>> 通过获取内容区域的 rect 的 top 值就是状态栏和标题栏的高度&#xff0c;也就可以得到标题栏的高度了&#xff0c; [java] view plaincopy int contentTop getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTo…

力扣—— 三维形体投影面积

在 N * N 的网格中&#xff0c;我们放置了一些与 x&#xff0c;y&#xff0c;z 三轴对齐的 1 * 1 * 1 立方体。 每个值 v grid[i][j] 表示 v 个正方体叠放在单元格 (i, j) 上。 现在&#xff0c;我们查看这些立方体在 xy、yz 和 zx 平面上的投影。 投影就像影子&#xff0c;将…

一图带你入门Linux 存储I/O栈

发现了一个内核大佬 的 Linux 存储I/O栈&#xff0c;很清晰&#xff01;&#xff01;&#xff01; 原地址如下&#xff1a; http://ilinuxkernel.com/?p1559 【侵删】

Java项目:在线美食网站系统(java+SSM+jsp+mysql+maven)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能&#xff1a;用户的注册登录&#xff0c;美食浏览&#xff0c;美食文化&#xff0c;收藏百 科&#xff0c;趣味问答&#xff0c;食谱等等功能等等。 二、项目运行 环境配置&#xff1a;…

性能测试中传——lr理论基础(四)

转载于:https://blog.51cto.com/fuwenchao/1346435

滑动定位的三种方法,以及热启动(五)

from init_driver.Init_driver import init_driverdriver init_driver()# 坐标-->坐标&#xff0c;定位滑动 driver.swipe(309, 1353, 537, 511, duration3000)# 元素-->元素&#xff0c;定位滑动 start_ele driver.find_element_by_xpath("//*[contains(text, 通…

TitanDB GC详细实现原理 及其 引入的问题

文章目录1. 为什么要有GC2. GC的触发条件3. GC的核心逻辑1. blob file形态2. GC Prepare3. GC pick file4. GC run4. GC 引入的问题5. Titan的测试代码通过本篇&#xff0c;能够从TitanDB的源代码中看到 key/value 分离之后引入的一些复杂性&#xff0c;这个复杂性很难避免。 …

Java项目:医院住院管理系统(java+SSM+jsp+mysql+maven)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能包括&#xff1a; 住院病人管理&#xff0c;住院病房管理&#xff0c;医生管理&#xff0c;药品管理&#xff0c;仪 器管理等等。 二、项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.…

1m网速是什么意思,1m带宽是什么意思

1M网速下载速度应是多少&#xff1f;我怎么才50多KB&#xff1f;&#xff1f; 建议: 一般来说是90到100算正常。最高能达到120 带究竟该有多快 揭开ADSL真正速度之谜 常常使用ADSL的用户&#xff0c;你知道ADSL的真正速度吗&#xff1f;带着这个疑问我们将问题一步一步展开。…

泛型实体类List绑定到repeater

泛型实体类List<>绑定到repeater 后台代码&#xff1a; private void bindnewslist(){long num 100L;List<Model.news> news _news.GetList(out num);this.newslist.DataSource news;this.newslist.DataBind();} 说明&#xff1a;Model.news是实体类&#xff0c…

Qt4.8.5移植

这两天搞了Qt移植 因为不小心 耽误了挺多时间 但是也比较好的掌握了 现在记录一下 准备工具&#xff1a; tslib-1.16 qt-everywhere-opensource-src-4.8.5.tar 下载路径&#xff1a; tslib-1.16下载&#xff1a; https://github.com/kergoth/tslib/releases/download/1.16/t…

Rocksdb 通过ingestfile 来支持高效的离线数据导入

文章目录前言使用方式实现原理总结前言 很多时候&#xff0c;我们使用数据库时会有离线向数据库导入数据的需求。比如大量用户在本地的一些离线数据&#xff0c;想要将这一些数据导入到已有的数据库中&#xff1b;或者说NewSQL场景中部分机器离线&#xff0c;重新上线之后的数…

Java项目:企业人事管理系统(java+SSM+jsp+mysql+maven)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能介绍&#xff1a;员工管理&#xff0c;用户管理&#xff0c;部门管理&#xff0c;文档管理, 职位管理等等。 二、项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 mysql Eclispe (I…

XCODE 6.1.1 配置GLFW

最近在学习opengl的相关知识。第一件事就是配环境(好烦躁)。了解了一下os x下的OpenGL开源库&#xff0c;主要有几个&#xff1a;GLUT&#xff0c;freeglut&#xff0c;GLFW等。关于其详细的介绍可以参考opengl网站(https://www.opengl.org/wiki/Related_toolkits_and_APIs)。由…

SpringCloud远程调用为啥要采用HTTP,而不是RPC?

通俗的说法就是:比如说现在有两台服务器A和B,一个应用部署在A服务器上,另一个应用部署在B服务器上,如果A应用想要调用B应用提供的方法,由于他们不在一台机器下,也就是说它们不在一个JVM内存空间中,是无法直接调用的,需要通过网络进行调用,那这个调用过程就叫做RPC。建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket ,套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

vs快捷键及常用设置(vs2012版)

vs快捷键&#xff1a; 1、ctrlf F是Find的简写&#xff0c;意为查找。在vs工具中按此快捷键&#xff0c;可以查看相关的关键词。比如查找哪些页面引用了某个类等。再配合查找范围&#xff08;整个解决方案、当前项目、当前文档等&#xff09;&#xff0c;可以快速的找到问题所在…

python_day10

小甲鱼python学习笔记 爬虫之正则表达式 1.入门&#xff08;要import re&#xff09; 正则表达式中查找示例&#xff1a; >>> import re >>> re.search(rFishC,I love FishC.com) <re.Match object; span(7, 12), matchFishC> >>> #单纯的这种…

Graphics2D API:Canvas操作

在中已经介绍了Canvas基本的绘图方法,本篇介绍一些基本的画布操作.注意:1、画布操作针对的是画布,而不是画布上的图形2、画布变换、裁剪影响后续图形的绘制,对之前已经绘制过的内容没有影响。

关于Titandb Ratelimiter 失效问题的一个bugfix

本文简单讨论一下在TitanDB 中使用Ratelimiter的一个bug&#xff0c;也算是一个重要bug了&#xff0c;相关fix已经提了PR到tikv 社区了pull-210。 这个问题导致的现象是ratelimiter 在titandb Flush/GC 生成blobfiled的过程中无法生效&#xff0c;也就是无法限制titandb的主要…

Java项目:前台预定+后台管理酒店管理系统(java+SSM+jsp+mysql+maven)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能介绍&#xff1a; 前台用户端&#xff1a;用户注册登录&#xff0c;房间展示&#xff0c;房间分类&#xff0c;房间 按价格区间查询&#xff0c;房间评论&#xff0c;房间预订等等 后台管…

Solr初始化源码分析-Solr初始化与启动

用solr做项目已经有一年有余&#xff0c;但都是使用层面&#xff0c;只是利用solr现有机制&#xff0c;修改参数&#xff0c;然后监控调优&#xff0c;从没有对solr进行源码级别的研究。但是&#xff0c;最近手头的一个项目&#xff0c;让我感觉必须把solrn内部原理和扩展机制弄…

iOS :UIPickerView reloadAllComponets not work

编辑信息页面用了很多选择栏&#xff0c;大部分都用 UIPickerView 来实现。在切换数据显示的时候&#xff0c; UIPickerView 不更新数据&#xff0c;不得其解。Google 无解&#xff0c;原因在于无法描述自己的问题&#xff0c;想想应该还是代码哪里写错了。 写了个测试方法&…

单相计量芯片RN8209D使用经验分享(转)

单相计量芯片RN8209D使用经验分享转载于:https://www.cnblogs.com/LittleTiger/p/10736060.html

git 对之前的commit 进行重新签名 Resign

在向开源社区提交PR的时候如果之前的提交忘记添加sign &#xff08;个人签名/公司签名&#xff09;&#xff0c;则社区的DCO检查会失败。 关于通过DCO检查能够确保以下几件事情生效&#xff1a; 你所提交的贡献是由你自己完成或者 你参与了其中&#xff0c;并且有权利按照开源…

【原创】linux命令bc使用详解

最近经常要在linux下做一些进制转换&#xff0c;看到了可以使用bc命令&#xff0c;如下: echo "obase10;ibase16;CFFF" | bc 用完以后就对bc进行了进一步的了解, man bc里面有详细的使用说明。 1.是什么,怎么用 bc - An arbitrary precision calculator language 一…

Java项目:学生信息管理系统(java+SSM+jsp+mysql+maven)

源码获取&#xff1a;博客首页 "资源" 里下载&#xff01; 一、项目简述 功能包括&#xff1a; 用户的登录注册&#xff0c;学生信息管理&#xff0c;教师信息管理&#xff0c;班级信 息管理&#xff0c;采用mvcx项目架构&#xff0c;覆盖增删改查&#xff0c;包括学…

MVC學習網站

http://www.cnblogs.com/haogj/archive/2011/11/23/2246032.html

数据导出Excel表格

public String exportInfoFr(String path,String name,String startdate,String enddate,SysUser user){List<Map<String, Object>> list this.esEntPermitErrDao.findListObjectBySql("select 字段值1,字段值2,字段值3,字段值4,字段值5 from 表名 where 字段…

Rocksdb 通过posix_advise 让内核减少在page_cache的预读

文章目录1. 问题排查确认I/O完全/大多数来自于rocksdb确认此时系统只使用了rocksdb的Get来读确认每次系统调用下发读的请求大小确认是否在内核发生了预读2. 问题原因内核预读机制page_cache_sync_readaheadondemand_readahead3. 优化事情起源于 组内的分布式kv 系统使用rocksdb…