nginx 安装和配置速记

安装 在 Ubuntu 下可以通过 apt-get 安装: sudo apt-get install nginx 安装完成后 nginx 会自动启动,这时候可以通过浏览器访问 80 端口。不出意外的话,就可以看到「Welcome to nginx!」的提示信息。 启动、关闭与重载配置 执行 nginx 命令可以直接启动 ngxin。如果 nginx 已经在运行,那么可能会出现端绑定错误提示。或者,nginx 默认的 80 端口被别的程序占用,那么也会出现这个错误。 在 nginx 已经在运行的情况下,可以通过 -s 参数对 nginx 进行控制: nginx -s signal 执行 nginx -s quit 或者 nginx -s stop 关闭 ngxin 服务。其中 quit 和 stop 的区别在于:quit 是平滑关闭,它会等待工作进程完成当前的请求之后再关闭进程,而 stop 则是强制关闭。 在对 nginx 的配置文件进行修改之后,需要执行 nginx -s reload 命令来充值配置文件,使修改生效。 配置 nginx 默认的配置文件是 /etc/nginx/nginx.conf。在这个文件中我们可以对 nginx 进行各种参数的配置。 这个文件里有 include /etc/nginx/sites-enabled/*; 这样一句话。这说明在这里加载了额外的配置文件。在 sites-enable 文件夹里只有一个 default 文件。它其实是一个软链接,指向了 /etc/nginx/sites-available/default。default 去掉无关信息之后的如下: ...

2017-06-15 · 2 min · 卡斯

Linux 笔记 — 使用 Screen 管理会话

基本使用 新建一个名为 kuma 的会话 screen -S kuma 列出当前所有会话 screen -ls 恢复名为 kuma 的会话 screen -r kuma 快捷键 ctrl+a d 断开(detach)当前会话 ctrl+a k 杀掉(kill)当前会话

2017-01-12 · 1 min · 卡斯

Boost date_time 库处理日期和时间

在游戏服务器端的开发工作中,很多时候我们不得不面对繁琐的日期和日期处理。比如说一个运营活动的开始和结束时间处理,还有一个限时道具的到期时间处理等等。如果恰好程序的开发语言是 C++,并且框架并没有对时间处理进行过合理的封装,那么这项工作看起来就不是那么轻松愉快了。这个时候使用 time_t 类型和 tm 结构体,进行原始的时间和日期的比较和计算,就俨然成了程序员的梦魇。不过好在写 Boost 的前辈们已经帮我们做了复杂的工作,然后封装成了这个date_time 库。用来真是爽歪歪啊~ date_time 概述 在使用 date_time 库之间,我们首先要明确三个基本概念:时间点(Time Point)、时长(Time Duration)、时段(Time Interval)。所谓时间点就是时间轴上的一个特定的点;时长就是两个时间点的差值,不属于时间轴;时段是两个特定时间点之间确定的区间。基本上所有的时间处理都是围绕的这三个概念进行的。这三者可以进行相互运算,例如时间点+时长=时间点,时长+时长=时长等。 处理日期 date_time 库的日期处理基于格里高利历, 支持从 1400-01-01 到 9999-12-31 之间的日期计算。为了使用 date_time 库的日期功能需要包含头文件 <boost/date_time/gregorian/gregorian.hpp>,即: #include <boost/date_time/gregorian/gregorian.hpp> using namespace boost::gregorian; date date 是 date_time 库处理日期的核心类,以天为单位表示时间点概念。 date d1(2001, 1, 1); //使用数字构造日期 date d2(2000, Jan, 1); //使用英文指定月份 date d3(d1); //date 支持拷贝构造 assert(d1 == d3); //date 支持比较操作 assert(d2 < d1); date 也可以从一个字符串产生: date d1 = from_string("1999-12-31"); date d2 = from_string("1999/12/31"); date d3 = from_undelimited_string("19991231"); day_clock day_clock 是一个天级别的时钟,它也是一个工厂类,调用它的静态成员函数 local_day() 或 universal_day() 会返回一个当天的时间对象,分别是本地日期和 UTC 日期。 date d1 = day_clock::local_day(); date d2 = day_clock::universal_day(); date_duration 日期长度是一天为单位的时长,基本的日期长度是 date_duration(days) ...

2016-08-27 · 1 min · 卡斯

LeetCode 003 — Longest Substring Without Repeating Characters

Longest Substring Without Repeating Characters https://leetcode.com/problems/longest-substring-without-repeating-characters/ 给定一个字符串,找出最长不重复子串的长度。 Solution 1 第一个解决方案依然采取最直观的方式,就是做两层遍历,从前往后逐个字符比较。 class Solution { public: int lengthOfLongestSubstring(string s) { int length = 0; for (int i = 0; i < s.length(); ++i) { int sub_length = 1; string sub_str = s.substr(i, sub_length); for (int j = i + 1; j < s.length(); ++j) { if (sub_str.find(s[j]) != string::npos) { break; } sub_str += s[j]; sub_length++; } if (sub_length > length) { length = sub_length; } } return length; } }; 提交代码,Accepted,但是 Runtime 164ms,太惨了… ...

2016-06-29 · 2 min · 卡斯

LeetCode 001 — Two Sum

最近开始撸 LeetCode,在这里做个简单的记录。撸 LeetCode 也不是因为闲来无事,只是觉得在工作之外需要继续锻炼。初步打算按照Problems 的题号来撸,Easy 优先,其他难度的撸不过可以先跳过,以后再来一遍也未尝不可,保持自信心比较重要。 Two Sum https://leetcode.com/problems/two-sum/ 题目大意是给定一个 int 数组,要求返回数组中两个数的下标值的数组,并且满足这两个数的和等于一个给定的目标值。并且假定每一个测试用例只有一个确定的结果。 Solution 1 这题最容易想到的方法,自然是最暴力的两个 for 循环的遍历,实现如下: class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { bool is_get = false; int i = 0; int j = 0; for (; i < nums.size(); i++) { for (j = i + 1; j < nums.size(); j++) { if (nums[i] + nums[j] == target) { is_get = true; break; } } if (is_get) { break; } } vector<int> v; v.push_back(i); v.push_back(j); return v; } }; 把这段代码提交上去,成功 Accepted 了,但是花费了688 ms。 ...

2016-03-22 · 2 min · 卡斯

泰拉瑞亚游戏存档路径修改

泰拉瑞亚(Terraria) 是一款非常受欢迎的2D沙盒游戏,甚至有不少玩家称之为 2D MineCraft。我久闻这款游戏的大名,所以早在半年前就从 Steam 上入了正版。但是非常遗憾的是,泰拉瑞亚的PC版没有合适的引导教程,导致入门有些门槛。比如说新手一进去不知道干什么,不知道如何使用道具、怎么砍树、怎么造房子,然后就在第一个夜晚到来的时候不停地被僵尸和眼球虐死。我自己本身也尝试了好几次,都没有摸索出合适的玩法,都没能入门玩起来,所以这款游戏就这么被我搁置了。 直到上个月,我无意中看到一个同事正在玩泰拉瑞亚的手机版,然后就下载了一个一起玩。令人意外的是手机版对于新手友好多了。手机版的开始菜单专门有一个教程栏目,点进去可以在一个教程地图上按照提示学习游戏的操作。除此之外游戏还特别针对移动版进行了优化,对一些在 PC 上比较复杂的操作在移动平台上进行了简化,大大降低了游戏的入门难度。还有一点令人惊讶的是,泰拉瑞亚的 Android 版和 iOS 版可以无缝局域网联机,甚至包括 iOS 盗版的。经过几天时间跟三四个同事一起联机摸索,我总算是入门了泰拉瑞亚。 长时间用手机玩泰拉瑞亚其实是一件挺累人的事,特别是挖矿和造房子。所以一段时间后,我又拉了几个同事一起玩 PC 版。一开始他们几个人玩的是汉化版的,我玩的是 Steam 英文版,这两个版本居然也是可以无缝局域网联机的,真是太棒了。由于游戏里的道具非常多,英文名字比较复杂,我拿到有些道具之后,不得不查词典,才能跟同事说我拿到的是什么。所以为了方便跟同事沟通,我后来也玩了汉化版的。 这里我碰到一个问题,就是 Steam 版和汉化版的游戏存档都存在 我的文档\My Games\Terraria\ 这个目录下,所以有些时候会发生冲突,造成游戏无法正常启动。所以我就想能不能把汉化版的存档目录修改一下,改成客户端所在目录,这样就方便多了。 先从客户端文件下手吧,把 Terraria.exe 扔到 PEiD 里查一下壳,发现这个东西没有加壳,是 C# 写的 .NET 程序。 既然知道是 .NET 程序,那我们就可以用 .NET Reflector 或者 ILSpy 来反编译分析。我以前没有尝试修改过 .NET 程序,这次也是新手上路。上述两个工具我都尝试过,但是在改完代码后保存可执行文件都或多或少出了一点问题。然后我找到了一个叫 JustDecompile 的反编译工具。这个工具跟大名鼎鼎的 Fiddler 是同一个公司出的,完全免费。下载安装 JustDecompile 后运行,打开 Plugins 菜单,安装 Assembly Editor 插件。这个插件其实就是 Refexlil,在上面两个工具里也可以使用这个插件,非常强大。 我们用 JustDecompile 打开 Terraria.exe, 然后点击 Open->Load Framewrok->Load .NET 4.6 Assemblies->x86 导入 x86 的 .NET 4.6 的库。接着打开 Search 菜单,左边的查找数据类型选择 Full Text, 然后查找 “My Games” 字符串。查找到一个结果,是一个名叫 GetStroragePath 的函数,双击这条结果,跳转到函数所在的代码。可以看到 JustDecompile 已经自动帮我们把反编译出来的 IL 代码转成了 C# 代码,这个函数的实现是这样的: ...

2016-01-19 · 1 min · 卡斯

后会无期

相聚有时,后会无期。

2014-07-18 · 1 min · 卡斯

判断点是否在多边形内 — 射线法

最近在工作中用到了这个算法,抽空做一个笔记。 判断一个点是否在多边形内部的问题在很多地方都会碰到,最常用的方法就是射线法。 射线法 以点P为端点,向左方作射线L,由于多边形是有界的,所以射线L的左端一定在多边形外,考虑沿着L从无穷远处开始自左向右移动,遇到和多边形的第一个交点的时候,进入到了多边形的内部,遇到第二个交点的时候,离开了多边形,…… 所以很容易看出当L和多边形的交点数目C是奇数的时候,P在多边形内,是偶数的话P在多边形外。 特殊情况 射线穿过多边形的顶点。 这个时候,这个顶点会被计算两次,这显然是不正确的。 解决方法是在射线上的顶点只在计算一次。为了达到这个目的,这里定义只有当一条边的一个端点在射线的下方,另一个端点在射线上或者射线的上方,我们才认为这条边与射线相交。这样一来,b边由于两个端点都在射线上或者在射线上方,因此被认为与射线不相交,而a边则与射线相交,那么这个顶点最终被计算了一次。 多边形的一条边在射线上。 这时候我们参照上面第一种情况的方法,可以得出d边和e边都被认为与射线不相交,而c边与射线相交。这样c边和d边中间的顶点只被统计了一次,此时也可以得出点在多边形内的正确结论。 其他情况。 这是另外两种特殊的情况,可以看到我们参照上面的计算方法,依然可以得出正确的结论。 给定的点在多边形的边上。 在这种情况下,射线法的结果是不确定的,可能得到的结果是点在多边形内也可能是点在多边形外。可以根据实际的应用要求在实现算法中先判断点是否在多边形的边上。 算法实现 C代码例子: // Globals which should be set before calling this function: // // int polySides = how many corners the polygon has // float polyX[] = horizontal coordinates of corners // float polyY[] = vertical coordinates of corners // float x, y = point to be tested // // (Globals are used in this example for purposes of speed. Change as // desired.) // // The function will return YES if the point x,y is inside the polygon, or // NO if it is not. If the point is exactly on the edge of the polygon, // then the function may return YES or NO. // // Note that division by zero is avoided because the division is protected // by the "if" clause which surrounds it. bool pointInPolygon() { int i, j = polySides - 1 ; bool oddNodes = NO ; for (i = 0; i < polySides; i++) { if (polyY[i] < y && polyY[j] >= y || polyY[j] < y && polyY[i] >= y) { if (polyX[i] + (y-polyY[i]) / (polyY[j]-polyY[i]) * (polyX[j]-polyX[i]) < x) { oddNodes =! oddNodes; }} j = i; } return oddNodes; } 这个C代码依次迭代多边形的每条边,判断是否与射线所在的直线相交(这里的相交表示边的两个端点一个在直线的下方,另个在直线上或者在直线上方)。如果边与直线相交,再判断边与直线的交点是否在测试点的左边(即射线上),这里的polyX[i]+(y-polyY[i])/(polyY[j]-polyY[i])*(polyX[j]-polyX[i])表示边与直线的交点的横坐标,可以通过线段所在直线的截距式方程和直线方程联立得出。 ...

2014-04-19 · 3 min · 卡斯