C1000K 实战,基于 Libev - 续

最近公司年终旅游,博客也是有很久没有更新了,这次继续我们上一次的高并发服务器编程。 上一篇文章讲解了要在Linux系统上实现C1000K服务器所需要进行的系统调优操作,那么我们现在就开始来编写我们的程序吧~ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 #include <arpa/inet.

对于 Task 并行操作所遇到的问题

直接贴代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Program { static List<TcpClient> list = new List<TcpClient>(); static string msg = "我是测试数据。"; static DynamicBufferManager buffer = new DynamicBufferManager(0); static void Main(string[] args) { buffer.WriteInt32(Encoding.UTF8.GetByteCount(msg), true); buffer.WriteString(msg); Console.WriteLine("输入创建的链接数目:"); int num = int.Parse(Console.ReadLine()); Console.WriteLine("正在创建连接..."); for (int i = 0; i < num; i++) { list.

C1000K 实战,基于 Libev

最近公司接到一个新项目,是基于Socket通信的GPS实时记录系统。实际设备台数是在20W左右,但是自己并没有对实时性要求这么高的高并发服务器软件设计经验,只能硬着头皮先进行测试开发试一下。 技术选型的话,当时是直接想使用Windows下面的IOCP,因为自己对C#这块比较熟悉,不过经过测试,在WindowsServer上面的测试结果并不理想,可能是自己水平不到家吧(笑)。关于高性能的IOCP编程大家可以参考这位仁兄的文章,写得很不错,而且也有实例:(C#高性能大容量SOCKET并发(一):IOCP完成端口例子介绍) 之后查阅了相关的技术资料和各类博客,发现Linux更适合做此类系统,所以选择了CentOS 7.x 64bit作为开发系统,高并发主要在于对Socket的监听一定要及时,所以Epoll是最好的选择。但是博主并不想直接再写一次Epoll了,相关Epoll进行高并发编程的可以参考**这篇文章**很不错的实例。所以我直接选择了Libev库作为底层的事件库,进行事件监听。 首先我们要实现C1000K的话,得对Linux的内核参数进行调优,怎么调? 第一步,调整系统单个进程最大打开的文件句柄数量: 1 vim /etc/security/limits.conf 在最末尾加入: 1 2 * soft nofile 1048576 * hard nofile 1048576 因为Linux下面一皆文件,即便是我们的Socket网络套接字也是属于文件句柄这个范畴的,默认大小可以通过ulimit -n查看,默认是1024个,对于我们百万并发的服务器来说显然是不够的。 这里的星号(*)代表的是对所有用户生效,当然你也可以手动指定用户,soft是警告阀值,而hard则是实际生效的阀值,在这里我们为了方便直接都改成一样的就可以了。 第二步,设置系统所有进程最多同时打开的句柄数量限制: 1 echo "fs.file-max = 1048576" >> /etc/sysctl.conf 之后执行以下命令使其生效: 1 sysctl -p 第三步,TCP参数调优: 1 2 3 echo "net.ipv4.tcp_mem = 786432 2097152 3145728" >> /etc/sysctl.conf echo "net.ipv4.tcp_rmem = 4096 4096 16777216" >> /etc/sysctl.conf echo "net.ipv4.tcp_wmem = 4096 4096 16777216" >> /etc/sysctl.conf tcp_rmem是TCP读取缓冲区,tcp_wmem是发送缓冲区,他们的单位都是字节,第一个是最小值,第二个是默认值,第三个是最大值,这里分别设置为4K,4K,16MB。 tcp_mem是TCP内存大小,单位是页,一页为4096字节。 low:当TCP使用了低于该值的内存页面数时,TCP不会考虑释放内存。 pressure:当TCP使用了超过该值的内存页面数量时,TCP试图稳定其内存使用,进入pressure模式,当内存消耗低于low值时则退出pressure状态。 high:允许所有tcp sockets用于排队缓冲数据报的页面量,当内存占用超过此值,系统拒绝分配socket,后台日志输出“TCP: too many of orphaned sockets”。 一般情况下这些值是在系统启动时根据系统内存数量计算得到的。 根据当前tcp_mem最大内存页面数是1864896,当内存为(1864896*4)/1024K=7284.

C# 如何实现URL编码?

经常我们在模拟HTTP请求的时候,需要对提交的参数进行URL编码。 在这里我们通过实现一个简单的扩展方法来完成这个功能~ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static class StringExplend { public static string ToURLEncoding(this string value) { if(!string.IsNullOrEmpty(value) { byte[] _strBytes = Encoding.UTF8.GetBytes(value); StringBuilder _sb = new StringBuilder(); foreach(var item in _strBytes) { _sb.Append(@"%",Convert.ToString(item,16)); // 当然在这里也可以使用 // _sb.Append(@"%" + item.ToString("x2")); } return _sb.ToString(); }else return string.Empty; } } 注意,这个方法有一个弊端,就是会将英文字符也进行转换,所以你需要手动过滤掉英文/数字。这里建议你选择使用在 System.Web 命名空间下的 HttpUtility 对象,使用方法很简单,如下: 1 2 3 4 public string URL_Encoding(string srcText, Encoding encoding) { return HttpUtility.

在 C# 当中实现 LRU Cache

在常用的缓存设计模式当中,LRU是比较简单且常见的一种缓存设计方案,简单说来就是在缓存队列当中,使用频率越低的对象,越会被踢出队列。原理的话很简单,我们有一个字典容器,还有一个双向链表。 字典容器则是我们缓存对象真正存储的地方,双向链表的作用则是用来记录当前缓存队列的使用频率情况,当用户命中一个缓存对象的时候,双向链表就回将这个对象的键ID放在最前面,这样就能够保证使用率最低的对象是存放在最末位。如果当我们添加了一个新的缓存对象的时候,但是字典容器满了,这个时候我们只需要找到双向链表当中最末位的那个缓存对象将其踢出队列,之后再将新的缓存对象存放到字典容器当中。 说了这么多,还是上代码吧: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 public class LRUCache<TKey,TValue> { private Dictionary<TKey,TValue> m_cache; private LinkedList<TKey> m_list; private ReaderWriterLockSlim m_locker; private int m_cacheSize; private const int Default_Size = 255; public LRUCache() : this(Default_Size){} public LRUCache(int cacheSize) { m_cache = new Dictionary<TKey,TValue>(); m_list = new LinkedList<TKey>(); m_locker = new ReaderWriterLockSlim(); m_cacheSize = cacheSize > 0 ?
Built with Hugo
主题 StackJimmy 设计