Joxon's

  • 首页

  • 关于

  • 归档

GitHub Pages + Hexo 博客搭建笔记

发表于 2018-08-09

前言

利用GitHub建博客早已不是什么新鲜事。此文用于记录本次建站的流程,顺便练习一下Markdown的用法。

在静态页面生成器的比较网站上以stars数量排序,前三位分别是:

  • Jekyll:Ruby实现
  • Hugo:Go实现
  • Hexo:Javascript实现

由于对Node.js多少有些经验,故选择了Hexo。

准备

  • Github 账号一个
  • Node.js 环境
  • Visual Studio Code

流程

GitHub

前往Github的个人页面创建一个新的仓库,名字为[username].github.io,其中[username]是注册Github时的用户名。一定要保证[username]和注册用户名相同,否则域名将不起作用,也就是说,一个账号只能拥有一个Github Page。

可以参考官方的指南作为Hello World。

Hexo

安装

假设我们已经配置好Node.js环境,windows用户一定要以管理员权限打开命令行窗口,全局安装hexo-cli到Node环境中:

1
npm install hexo-cli -g

安装成功后,找一个喜欢的目录,初始化一个hexo项目,[folder]是项目名字:

1
hexo init [folder]

然后改变当前工作目录为刚刚新建的[folder]:

1
cd [folder]

安装项目依赖:

1
npm install

到此,hexo项目已经安装完毕,可以开始撰文或进行参数调节。

撰文

执行hexo new [title],新建一篇md格式的文档,开始编写。

hexo new可以简写为hexo n

预览

执行hexo server可以在本地搭建服务器,可以在浏览器预览自己的博客。

hexo server可以简写为hexo s。

生成

执行hexo generate可以生成博客的静态文件。

hexo generate可以简写为hexo g。

部署

执行hexo deploy可以把博客部署到指定的位置,这里需要配置_config.yml中的deploy参数。

示例如下:

1
2
3
4
5
deploy:
type: git
repo: https://github.com/user/user.github.io.git
branch: master
message: "Site updated: {{ now('YYYY-MM-DD HH:mm:ss') }}"

hexo deploy可以简写为hexo d。

Hello Hexo!

发表于 2018-08-09

2018-08-09,从 cnblogs 转移到 Github。

利用cnblogs的备份功能导出 XML,然后利用hexo-migrator-rss导入 XML 即可。

MariaDB + Visual Studio 2017 环境下的 ODBC 入门开发

发表于 2018-05-06 | 更新于 2018-08-09

参考:

Easysoft公司提供的ODBC教程

微软提供的ODBC文档

环境:

  • Windows 10 x64 1803
  • MariaDB TX 10.2.14 x64
  • MariaDB ODBC Connector 3.0.3 x64
  • Visual Studio 2017 Community 15.6.7

安装ODBC驱动并配置数据源:

先安装ODBC驱动。根据自身需求选择32或64位版本。我选择了64位版本。

打开ODBC数据源管理程序,点击右侧的“添加”按钮,添加用户DSN。如图操作。

后面按照默认配置,点击Next即可。

编写ODBC程序:

1         引入头文件:


#include <iostream>

#include
<windows.h>

#include
<sqlext.h>

2         定义一个检查错误的宏:


#define ODBC_CHECK(x) \

{\

if (!SQL_SUCCEEDED(x))\

{\

std::cout
<< “SQL error occurred at line “ << LINE << “.“;\

getchar();\

exit(
-1);\

}\

}

3         ODBC初始化,为ODBC分配环境句柄

(分配环境句柄:注意,这里使用了新版的ODBC API SQLAllocHandle**,而不是SQLAllocEnv**)


    // SQL Handle of ENVironment

SQLHENV env;

ODBC_CHECK(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE,
&env)); // SQLAllocEnv

  ODBC_CHECK(SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3,
0));

4         建立应用程序与ODBC数据源的连接

(分配连接句柄:注意,这里使用了新版的ODBC API SQLAllocHandle**,而不是SQLAllocConnect**)


    // SQL Handle of DB Connection

SQLHDBC dbc;

SQLCHAR dbcConfOut[
256];

ODBC_CHECK(SQLAllocHandle(SQL_HANDLE_DBC, env,
&dbc)); // SQLAllocConnect

ODBC_CHECK(SQLSetConnectAttr(dbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)
5, 0));

(连接数据源:可以使用SQLConnect**,也可以使用SQLDriverConnect;可以手动指定DSN名字,也可以通过弹出窗口来指定)**


    // specify manually

ODBC_CHECK(SQLDriverConnect(dbc, NULL, (SQLCHAR
*)“DSN=MariaDB;“, SQL_NTS,

dbcConfOut,
sizeof(dbcConfOut), NULL, SQL_DRIVER_COMPLETE)); // SQLConnect

// specify by popup window

//ODBC_CHECK(SQLDriverConnect(dbc, GetDesktopWindow(), NULL, SQL_NTS,

// dbcConfOut, sizeof(dbcConfOut), NULL, SQL_DRIVER_COMPLETE)); // SQLConnect

(显示连接成功的信息)


    std::cout << “Connected!“ << std::endl

<< “ConnStrIn = “ << dbcConfOut << std::endl;

SQLCHAR dbmsName[
256];

ODBC_CHECK(SQLGetInfo(dbc, SQL_DBMS_NAME, (SQLPOINTER)dbmsName,
sizeof(dbmsName), NULL));

SQLCHAR dbmsVer[
256];

ODBC_CHECK(SQLGetInfo(dbc, SQL_DBMS_VER, (SQLPOINTER)dbmsVer,
sizeof(dbmsVer), NULL));

std::cout
<< “DBMS Name = “ << dbmsName << std::endl

<< “DBMS Version = “ << dbmsVer << std::endl;

(分配语句句柄:注意,这里使用了新版的ODBC API SQLAllocHandle**,而不是SQLAllocStmt**)


    // SQL Handle of STateMenT

SQLHSTMT stmt;

ODBC_CHECK(SQLAllocHandle(SQL_HANDLE_STMT, dbc,
&stmt)); // SQLAllocStmt

5         利用SQLExecDirect语句,实现数据库应用程序对数据库的建立、查询、修改、删除等 

(建立一个循环,一直接收并执行用户的SQL**的语句,直到用户退出)**


    const int queryLen = 1024;

SQLCHAR query[queryLen];

std::cout
<< “Please input your SQL query. Type CTRL+Z to quit.“ << std::endl

<< dbmsName << “ >“;

while (fgets((char*)query, queryLen - 1, stdin))

{

if (query[0] == ‘\n‘)

{

std::cout
<< dbmsName << “ >“;

continue;

}

switch (SQLExecDirect(stmt, query, SQL_NTS))

{

case SQL_SUCCESS_WITH_INFO:

case SQL_SUCCESS:

{

SQLSMALLINT col;

SQLNumResultCols(stmt,
&col);

// SELECT

if (col > 0)

{
// 2 methods: SQLGetData() and SQLBindCol()

// SQLGetData() is adopted here

char buf[512];

SQLUSMALLINT colidx;

// print column names

for (colidx = 1; colidx <= col; ++colidx)

{

SQLColAttribute(stmt, colidx, SQL_DESC_NAME,

buf,
sizeof(buf), NULL, NULL);

std::cout
<< buf << “ “;

}

std::cout
<< std::endl;

// iterate each row

unsigned row
= 0; // row counter

while (SQL_SUCCEEDED(SQLFetch(stmt)))

{

++row;

// iterate each column

for (colidx = 1; colidx <= col; ++colidx)

{

SQLLEN indicator;

if (SQL_SUCCEEDED(SQLGetData(stmt, colidx, SQL_C_CHAR,

buf,
sizeof(buf), &indicator)))

{

if (indicator == SQL_NULL_DATA) strcpy(buf, “NULL“);

std::cout
<< buf << “ “;

}

}

std::cout
<< std::endl;

}

if (row == 1) { std::cout << “1 row in set.“ << std::endl; }

else { std::cout << row << “ rows in set.“ << std::endl; }

}

// CREATE, UPDATE, DELETE, etc.

else

{

SQLLEN row;

ODBC_CHECK(SQLRowCount(stmt,
&row));

if (row == 1) { std::cout << “1 row affected.“ << std::endl; }

else { std::cout << row << “ rows affected.“ << std::endl; }

}

break;

}

case SQL_ERROR:

{

std::cout
<< “Returned SQL_ERROR.“ << std::endl;

break;

}

default:

{

std::cout
<< “Unknown SQLRETURN.“ << std::endl;

}

}

ODBC_CHECK(SQLFreeStmt(stmt, SQL_CLOSE));

std::cout
<< dbmsName << “ >“;

}

6         检索查询结果集 

7         结束数据库应用程序


    // release resources

ODBC_CHECK(SQLFreeHandle(SQL_HANDLE_STMT, stmt));

ODBC_CHECK(SQLDisconnect(dbc));

ODBC_CHECK(SQLFreeHandle(SQL_HANDLE_DBC, dbc));

ODBC_CHECK(SQLFreeHandle(SQL_HANDLE_ENV, env));

return 0;

 

CUDA 9.1/9.2 与 Visual Studio 2017 (VS2017 15.6.4) 的不兼容问题

发表于 2018-03-25 | 更新于 2018-08-09

2018年7月9日更新:

CUDA已推出9.2版本,最高支持MSVC++ 14.13 _MSC_VER == 1913 (Visual Studio 2017 version 15.6)。

然而最新版本是MSVC++ 14.14 _MSC_VER == 1914 (Visual Studio 2017 version 15.7),可见CUDA总比VS要慢一拍。

环境:

CUDA Toolkit - v9.1.85

Visual Studio 2017 (VS2017 15.6.4) + 平台工具集 v141(version 14.12,_MSC_VER=1912)或

CUDA Toolkit - v9.2.88.1

MSVC++ 14.13 _MSC_VER == 1913 (Visual Studio 2017 version 15.6)

原因:

CUDA未能兼容最新版工具集。

打开C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.1\include\crt\host_config.h,定位到133行:

可以看到当前CUDA支持的工具集版本。

由于当前工具集版本为1912,故无法兼容。修改_MSC_VER > 1911为更高的数字可以消除报错,但是编译仍然是无法通过的。

解决方案:

安装兼容的工具集版本。在这里,我们可以选择1900、1910、1911版本工具集。

打开Visual Studio Installer,选择相应的工具集进行安装。

然后修改项目工具集即可。

参见:

https://blog.csdn.net/shenpibaipao/article/details/79519533

https://devtalk.nvidia.com/default/topic/1027299/cuda-9-failed-to-support-the-latest-visual-studio-2017-version-15-5/

https://blogs.msdn.microsoft.com/vcblog/2017/11/15/side-by-side-minor-version-msvc-toolsets-in-visual-studio-2017/

VPS 上搭建 SSR 及其使用之心得

发表于 2017-07-06 | 更新于 2018-08-09

最近部署在ipv4上的SS经常断流,感觉是被Wa11检测出来了,所以转为SSR。

环境:

  • 网络:ipv4 北京联通 / ipv6 CERNET2
  • 服务器端:centOS 7 x86_64 + ShadowsocksR 3.1.2
  • windows客户端:shadowsocksr-csharp 4.6.1
  • android客户端:shadowsocksr-android 3.4.0.5

服务器端:

  参见官方教程:ShadowsocksR 服务端安装教程

备忘:

推荐协议:auth_chain_a

推荐混淆:tls1.2_ticket_auth

 

VPS 上搭建 Kcptun 及其使用之心得

发表于 2017-03-19 | 更新于 2018-08-09

最近成功在centOS6的VPS上成功开启kcptun。SS加速效果显著。下面记录一下服务器端安装与客户端使用过程。

环境:

  • 网络:ipv4北京联通 / ipv6CERNET2
  • 服务器端:centOS 6 + shadowsocks-libev 2.5.5
  • windows客户端:shadowsocks-windows 3.4.3 + kcptun_gclient by dfdragon 1.1.1 + kcptun by xtaci 20170315
  • android客户端:shadowsocks-android 4.1.3 + kcptun plugin (最新版客户端取消了对kcptun的内置)

服务器端:

  1. 使用了扩软博客提供的脚本,网址:kcptun服务端一键安装脚本
  2. 基础的调整参数有:

    • 服务器需要被加速的端口(此处为SS端口)
    • kcptun监听的端口
    • 传输模式
    • 加密模式
    • 加密密码
  3. 安装成功即可开始使用kcptun,以后可以根据需求调整高级参数。

Windows客户端:

下载控制台版本的kcptun(必选)及其控制界面(可选)。此处采用kcptun_gclient by dfdragon,截图如下:

  首先定位找到控制台版本的kcptun客户端。本地侦听端口可任意选择一个未被占用的端口。服务器地址填入VPS的IP地址,ipv6地址需要用[]括起。端口填入VPS上kcptun的监听端口。最后输入加密信息,即完成对kcptun的配置。点击“启动”,若输出没有报错,kcptun客户端就启动成功了。

  然后对ss进行简单配置。让本地的kcptun客户端代理ss的流量。

  切换ss的服务器为kcptun,若观察到stream opened字样则已经可以正常使用。

Android客户端:

  由于最新版ss取消了对kcptun的内置,我们需要到Google Play下载相应的kcptun插件。插件安装成功后,在configure一栏填入相关参数:

  remoteaddr填入“服务器IP:端口”(不用引号),key填入加密密码,crypt为加密方式,其余默认。测试可正常使用。

效果对比:

测试环境:ipv6校园网

测试内容:ytb视频

加速前

加速后,连接速率提高了超十倍

配置分享:

请根据个人情况进行调节!各参数意义可以参考kcptun的各个issue

 服务器端:


{
“listen”: “:端口”,
“target”: “127.0.0.1:端口”,
“key”: “密码”,
“crypt”: “加密方式”,
“mode”: “fast2”,
“mtu”: 1400,
“sndwnd”: 1024,
“rcvwnd”: 1024,
“datashard”: 0,
“parityshard”: 0,
“dscp”: 46,
“nocomp”: true,
“acknodelay”: false,
“nodelay”: 0,
“interval”: 20,
“resend”: 2,
“nc”: 1,
“sockbuf”: 4194304,
“keepalive”: 10
}

客户端:


{
“localaddr”:”:端口”,
“remoteaddr”:”VPS地址:端口”,
“key”:”密码”,
“crypt”:”加密方式”,
“nocomp”:true,
“datashard”:0,
“parityshard”:0,
“mtu”:1400,
“sndwnd”:1024,
“rcvwnd”:1024,
“dscp”:46,
“mode”:”fast2”,
“nodelay”:0,
“nc”:0,
“acknodelay”:false
}

PS@2017-03-23:测试了30(datashard)/15(parityshard)的FEC配置,仍然感觉0/0速率最高。

 

 

 :

 

用 SDL2 在屏幕上打印文本

发表于 2016-06-06 | 更新于 2018-08-09

打印完图片,是时候打印文字了。这里引用了SDL的字体扩展库,SDL2_ttf.lib,需要包含相应的头文件。

环境:SDL2 + VC++2015

下面的代码将在窗口打印一段文字,并对相应的操作做出响应。

这次把错误处理给精简掉了,代码看起来更清爽。


 1 #include <iostream>
2 #include “SDL.h“
3 #include “SDL_ttf.h“
4
5 int main(int argc, char* argv)
6 {
7 //屏幕宽度
8 const int SCREEN_WIDTH = 680;
9 const int SCREEN_HEIGHT = 400;
10 //初始化SDL
11 SDL_Init(SDL_INIT_EVERYTHING);
12 //初始化字体库
13 TTF_Init();
14 //创建窗口
15 SDL_Window
window = SDL_CreateWindow(“Font Test“,
16 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
17 SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
18 //创建渲染器
19 SDL_Renderer renderer = SDL_CreateRenderer(window, -1,
20 SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
21
22 //打开字体
23 TTF_Font
font = TTF_OpenFont(“XHei.TTC“, 30);
24 //文本转表面
25 SDL_Color color = { 255, 255, 255 };
26 SDL_Surface surf = TTF_RenderText_Blended(font, “Cool, Cooler, Coolest!“, color);
27 //表面转纹理
28 SDL_Texture
text = SDL_CreateTextureFromSurface(renderer, surf);
29 //释放资源
30 SDL_FreeSurface(surf);
31 TTF_CloseFont(font);
32
33 bool quit = false;
34 SDL_Event e;
35 //主循环
36 while (!quit)
37 {
38 //事件栈轮询
39 while (SDL_PollEvent(&e))
40 {
41 //按右上角的X或点鼠标退出
42 if (e.type == SDL_QUIT || e.type == SDL_MOUSEBUTTONDOWN) quit = true;
43 //清空渲染器
44 SDL_RenderClear(renderer);
45 //渲染字体
46 SDL_RenderCopy(renderer, text, NULL, NULL);
47 //呈现渲染器
48 SDL_RenderPresent(renderer);
49 }
50 }
51
52 //释放资源
53 SDL_DestroyTexture(text);
54 SDL_DestroyRenderer(renderer);
55 SDL_DestroyWindow(window);
56
57 SDL_Quit();
58
59 return 0;
60 }

 

用 SDL2 处理精灵图

发表于 2016-06-05 | 更新于 2018-08-09

上面就是一个精灵图,由多个固定间隔的图标组成。利用精灵图的好处就是不必将图标逐个读入内存进行操作。我们可以将精灵图中需要的部分用一个个矩形截取下来,然后再输出到渲染器上。

环境:SDL2 + VC++2015

下面的代码将打开sprite.png,并对相应的操作做出响应。

sprite.png


  1 #include <stdexcept>
2 #include <string>
3 #include <iostream>
4 #include “SDL.h“
5 #include “SDL_image.h“
6
7 //屏幕宽度
8 const int SCREEN_WIDTH = 500;
9 const int SCREEN_HEIGHT = 500;
10
11 //全局窗口和渲染器
12 SDL_Window window = nullptr;
13 SDL_Renderer
renderer = nullptr;
14
15 //记录SDL错误
16 void logSDLError(std::ostream &os, const std::string &msg)
17 {
18 os << msg << “ error: “ << SDL_GetError() << std::endl;
19 }
20
21 //加载图像材质
22 SDL_Texture loadTexture(const std::string &file, SDL_Renderer ren)
23 {
24 SDL_Texture texture = IMG_LoadTexture(ren, file.c_str());
25 if (texture == nullptr) logSDLError(std::cout, “LoadTexture“);
26 return texture;
27 }
28
29
30 //根据坐标生成截取区域并复制输出到渲染器
31 void renderTexture(SDL_Texture
tex, SDL_Renderer ren, int x, int y, SDL_Rect clip = nullptr)
32 {
33 //目标截面区域初始化,提供目标在渲染器的坐标
34 SDL_Rect dst; dst.x = x; dst.y = y;
35 //源截面区域不为空,将其值赋给目标截面
36 if (clip != nullptr) { dst.w = clip->w; dst.h = clip->h; }
37 //将截面输出到渲染器
38 SDL_RenderCopy(ren, tex, clip, &dst);
39 }
40
41 int main(int argc, char* argv)
42 {
43 //初始化SDL
44 if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
45 {
46 std::cout << SDL_GetError() << std::endl;
47 return 1;
48 }
49
50 //创建窗口
51 window = SDL_CreateWindow(“Lesson 5“,
52 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
53 SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
54 if (window == nullptr)
55 {
56 std::cout << SDL_GetError() << std::endl;
57 return 2;
58 }
59
60 //创建渲染器
61 renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
62 if (renderer == nullptr)
63 {
64 std::cout << SDL_GetError() << std::endl;
65 return 3;
66 }
67
68 //创建纹理
69 SDL_Texture
image = nullptr;
70 try
71 {
72 image = loadTexture(“sprite.png“, renderer);
73 }
74 catch (const std::runtime_error &e)
75 {
76 std::cout << e.what() << std::endl;
77 return 4;
78 }
79
80 //iW,iH 表示截面宽高
81 int iW = 100, iH = 100;
82 //x,y 分别为截面在渲染器输出的坐标
83 int x = SCREEN_WIDTH / 2 - iW / 2;
84 int y = SCREEN_HEIGHT / 2 - iH / 2;
85
86 //为精灵图设置截面
87 SDL_Rect clips[4];
88
89 //初始化截面信息
90 for (int i = 0; i < 4; ++i)
91 {
92 clips[i].x = i / 2 iW;
93 clips[i].y = i % 2
iH;
94 clips[i].w = iW;
95 clips[i].h = iH;
96 }
97
98 //表示将要输出的截面
99 int useClip = 0;
100
101 SDL_Event e;
102 bool quit = false;
103 //主循环
104 while (!quit)
105 {
106 //事件轮询
107 while (SDL_PollEvent(&e))
108 {
109 //按右上角的X退出
110 if (e.type == SDL_QUIT) quit = true;
111
112 //点击鼠标随机输出截面
113 if (e.type == SDL_MOUSEBUTTONDOWN) useClip = rand() % 4;
114
115 //使用数字键决定输出截面,分别有1,2,3,4
116 if (e.type == SDL_KEYDOWN)
117 {
118 switch (e.key.keysym.sym)
119 {
120 case SDLK_1:
121 case SDLK_KP_1:
122 useClip = 0;
123 break;
124 case SDLK_2:
125 case SDLK_KP_2:
126 useClip = 1;
127 break;
128 case SDLK_3:
129 case SDLK_KP_3:
130 useClip = 2;
131 break;
132 case SDLK_4:
133 case SDLK_KP_4:
134 useClip = 3;
135 break;
136 case SDLK_ESCAPE:
137 quit = true;
138 break;
139 default:
140 break;
141 }
142 }
143 }
144 //清空渲染器
145 SDL_RenderClear(renderer);
146 //绘制材质
147 renderTexture(image, renderer, x, y, &clips[useClip]);
148 //呈现渲染器
149 SDL_RenderPresent(renderer);
150 }
151
152 //释放资源
153 SDL_DestroyTexture(image);
154 SDL_DestroyRenderer(renderer);
155 SDL_DestroyWindow(window);
156
157 SDL_Quit();
158
159 return 0;
160 }

 

用 SDL2 进行事件驱动编程

发表于 2016-06-05 | 更新于 2018-08-09

其实没必要说得太复杂…就是读取用户输入啦。

沿用上一篇的代码,加入事件轮询。

环境:SDL2 + VC++2015

下面的代码将打开background.png和event.png,将background平铺背景,将event作为前景呈现。


  1 #include <stdexcept>
2 #include <string>
3 #include <iostream>
4 #include “SDL.h“
5 #include “SDL_image.h“
6
7 //屏幕宽度
8 const int SCREEN_WIDTH = 1600;
9 const int SCREEN_HEIGHT = 900;
10
11 //全局窗口和渲染器
12 SDL_Window window = nullptr;
13 SDL_Renderer
renderer = nullptr;
14
15 //加载图片
16 SDL_Texture LoadImage(std::string file)
17 {
18 SDL_Texture
tex = nullptr;
19 tex = IMG_LoadTexture(renderer, file.c_str());
20 if (tex == nullptr)
21 throw std::runtime_error(“Failed to load image: “ + file + IMG_GetError());
22 return tex;
23 }
24
25 //将表面应用到渲染器
26 void ApplySurface(int x, int y, SDL_Texture tex, SDL_Renderer rend)
27 {
28 SDL_Rect pos;
29 pos.x = x;
30 pos.y = y;
31 SDL_QueryTexture(tex, NULL, NULL, &pos.w, &pos.h);
32 SDL_RenderCopy(rend, tex, NULL, &pos);
33 }
34
35 int main(int argc, char* argv)
36 {
37 //初始化SDL
38 if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
39 {
40 std::cout << SDL_GetError() << std::endl;
41 return 1;
42 }
43
44 //创建窗口
45 window = SDL_CreateWindow(“Lesson 4 - Event Driven Programming“,
46 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
47 SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
48 if (window == nullptr)
49 {
50 std::cout << SDL_GetError() << std::endl;
51 return 2;
52 }
53
54 //创建渲染器
55 renderer = SDL_CreateRenderer(window, -1,
56 SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
57 if (renderer == nullptr)
58 {
59 std::cout << SDL_GetError() << std::endl;
60 return 3;
61 }
62
63 //创建背景和前景纹理
64 SDL_Texture
background = nullptr, *image = nullptr;
65 try {
66 background = LoadImage(“background.png“);
67 image = LoadImage(“event.png“);
68 }
69 catch (const std::runtime_error &e) {
70 std::cout << e.what() << std::endl;
71 return 4;
72 }
73
74 bool quit = false;
75 SDL_Event e;
76 //主循环(CPU高占用)
77 while (!quit)
78 {
79 //轮询事件栈e
80 while (SDL_PollEvent(&e))
81 {
82 //用户关闭窗口
83 if (e.type == SDL_QUIT) quit = true;
84
85 //用户按下键盘
86 if (e.type == SDL_KEYDOWN) quit = true;
87
88 //用户点击鼠标
89 if (e.type == SDL_MOUSEBUTTONDOWN) quit = true;
90
91 //清空渲染器
92 SDL_RenderClear(renderer);
93
94 //在渲染器内平铺背景
95 int bW, bH;
96 SDL_QueryTexture(background, NULL, NULL, &bW, &bH);
97 for (int y = 0; y <= SCREEN_HEIGHT; y += bH)
98 for (int x = 0; x <= SCREEN_WIDTH; x += bW)
99 ApplySurface(x, y, background, renderer);
100
101
102 //在渲染器中央放置前景
103 int iW, iH;
104 SDL_QueryTexture(image, NULL, NULL, &iW, &iH);
105 int x = SCREEN_WIDTH / 2 - iW / 2;
106 int y = SCREEN_HEIGHT / 2 - iH / 2;
107 ApplySurface(x, y, image, renderer);
108
109 //呈现渲染器
110 SDL_RenderPresent(renderer);
111 }
112 }
113
114 //释放资源
115 SDL_DestroyTexture(background);
116 SDL_DestroyTexture(image);
117 SDL_DestroyRenderer(renderer);
118 SDL_DestroyWindow(window);
119
120 SDL_Quit();
121
122 return 0;
123 }

 

用 SDL2 加载PNG平铺背景并显示前景

发表于 2016-06-05 | 更新于 2018-08-09

上一篇中加载的是BMP,这次可以引用 SDL2_image.lib,加载更多格式的图像。

LoadImage函数做了改动,区别在于不用将surface转换成texture了。

环境:SDL2 + VC++2015

下面的代码将打开background.png和image.png,将background平铺背景,将image作为前景呈现。


  1 #include <stdexcept>
2 #include <string>
3 #include <iostream>
4 #include “SDL.h“
5 #include “SDL_image.h“
6
7 //屏幕宽度
8 const int SCREEN_WIDTH = 1600;
9 const int SCREEN_HEIGHT = 900;
10
11 //全局窗口和渲染器
12 SDL_Window window = nullptr;
13 SDL_Renderer
renderer = nullptr;
14
15 //加载图片
16 SDL_Texture LoadImage(std::string file)
17 {
18 SDL_Texture
tex = nullptr;
19 tex = IMG_LoadTexture(renderer, file.c_str());
20 if (tex == nullptr)
21 throw std::runtime_error(“Failed to load image: “ + file + IMG_GetError());
22 return tex;
23 }
24
25 //将表面应用到渲染器
26 void ApplySurface(int x, int y, SDL_Texture tex, SDL_Renderer rend)
27 {
28 SDL_Rect pos;
29 pos.x = x;
30 pos.y = y;
31 SDL_QueryTexture(tex, NULL, NULL, &pos.w, &pos.h);
32 SDL_RenderCopy(rend, tex, NULL, &pos);
33 }
34
35 int main(int argc, char* argv)
36 {
37 //初始化SDL
38 if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
39 {
40 std::cout << SDL_GetError() << std::endl;
41 return 1;
42 }
43
44 //创建窗口
45 window = SDL_CreateWindow(“Lesson 3“,
46 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
47 SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
48 if (window == nullptr)
49 {
50 std::cout << SDL_GetError() << std::endl;
51 return 2;
52 }
53
54 //创建渲染器
55 renderer = SDL_CreateRenderer(window, -1,
56 SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
57 if (renderer == nullptr)
58 {
59 std::cout << SDL_GetError() << std::endl;
60 return 3;
61 }
62
63 //创建背景和前景纹理
64 SDL_Texture
background = nullptr, *image = nullptr;
65 try {
66 background = LoadImage(“background.png“);
67 image = LoadImage(“image.png“);
68 }
69 catch (const std::runtime_error &e) {
70 std::cout << e.what() << std::endl;
71 return 4;
72 }
73
74 //清空渲染器
75 SDL_RenderClear(renderer);
76
77 //在渲染器内平铺背景
78 int bW, bH;
79 SDL_QueryTexture(background, NULL, NULL, &bW, &bH);
80 for (int y = 0; y <= SCREEN_HEIGHT; y += bH)
81 for (int x = 0; x <= SCREEN_WIDTH; x += bW)
82 ApplySurface(x, y, background, renderer);
83
84
85 //在渲染器中央放置前景
86 int iW, iH;
87 SDL_QueryTexture(image, NULL, NULL, &iW, &iH);
88 int x = SCREEN_WIDTH / 2 - iW / 2;
89 int y = SCREEN_HEIGHT / 2 - iH / 2;
90 ApplySurface(x, y, image, renderer);
91
92 //呈现渲染器
93 SDL_RenderPresent(renderer);
94 SDL_Delay(2000);
95
96 //释放资源
97 SDL_DestroyTexture(background);
98 SDL_DestroyTexture(image);
99 SDL_DestroyRenderer(renderer);
100 SDL_DestroyWindow(window);
101
102 SDL_Quit();
103
104 return 0;
105 }

 

用 SDL2 平铺背景并显示前景

发表于 2016-06-05 | 更新于 2018-08-09

环境:SDL2 + VC++2015

下面的代码将打开background.bmp和image.bmp,将background平铺背景,将image作为前景呈现


  1 #include <iostream>
2 #include “SDL.h“
3
4 //屏幕宽度
5 const int SCREEN_WIDTH = 640;
6 const int SCREEN_HEIGHT = 480;
7
8 //全局窗口和渲染器
9 SDL_Window window = nullptr;
10 SDL_Renderer
renderer = nullptr;
11
12 //加载图片
13 SDL_Texture LoadImage(std::string file)
14 {
15 SDL_Surface
loadedImage = nullptr;
16 SDL_Texture texture = nullptr;
17
18 loadedImage = SDL_LoadBMP(file.c_str());
19 if (loadedImage != nullptr)
20 {
21 texture = SDL_CreateTextureFromSurface(renderer, loadedImage);
22 SDL_FreeSurface(loadedImage);
23 }
24 else
25 std::cout << SDL_GetError() << std::endl;
26 return texture;
27 }
28
29 //将表面应用到渲染器
30 void ApplySurface(int x, int y, SDL_Texture
tex, SDL_Renderer rend)
31 {
32 SDL_Rect pos;
33 pos.x = x;
34 pos.y = y;
35 SDL_QueryTexture(tex, NULL, NULL, &pos.w, &pos.h);
36 SDL_RenderCopy(rend, tex, NULL, &pos);
37 }
38
39 int main(int argc, char** argv)
40 {
41 //初始化SDL
42 if (SDL_Init(SDL_INIT_EVERYTHING) == -1)
43 {
44 std::cout << SDL_GetError() << std::endl;
45 return 1;
46 }
47
48 //创建窗口
49 window = SDL_CreateWindow(“Lesson 2“,
50 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
51 SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
52 if (window == nullptr)
53 {
54 std::cout << SDL_GetError() << std::endl;
55 return 2;
56 }
57
58 //创建渲染器
59 renderer = SDL_CreateRenderer(window, -1,
60 SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
61 if (renderer == nullptr)
62 {
63 std::cout << SDL_GetError() << std::endl;
64 return 3;
65 }
66
67 //创建背景和前景纹理
68 SDL_Texture
background = nullptr, *image = nullptr;
69 background = LoadImage(“background.bmp“);
70 image = LoadImage(“image.bmp“);
71 if (background == nullptr || image == nullptr)
72 return 4;
73
74 //清空渲染器
75 SDL_RenderClear(renderer);
76
77 //在渲染器内平铺背景
78 int bW, bH;
79 SDL_QueryTexture(background, NULL, NULL, &bW, &bH);
80 ApplySurface(0, 0, background, renderer);
81 ApplySurface(bW, 0, background, renderer);
82 ApplySurface(0, bH, background, renderer);
83 ApplySurface(bW, bH, background, renderer);
84
85 //在渲染器中央放置前景
86 int iW, iH;
87 SDL_QueryTexture(image, NULL, NULL, &iW, &iH);
88 int x = SCREEN_WIDTH / 2 - iW / 2;
89 int y = SCREEN_HEIGHT / 2 - iH / 2;
90 ApplySurface(x, y, image, renderer);
91
92 //呈现渲染器
93 SDL_RenderPresent(renderer);
94 SDL_Delay(2000);
95
96 //释放资源
97 SDL_DestroyTexture(background);
98 SDL_DestroyTexture(image);
99 SDL_DestroyRenderer(renderer);
100 SDL_DestroyWindow(window);
101
102 SDL_Quit();
103
104 return 0;
105 }

 彩蛋:

如果窗口变成了1920*1080呢?上面的平铺方法就不够灵活了。试下:


1     int bW, bH;
2 SDL_QueryTexture(background, NULL, NULL, &bW, &bH);
3 for (int y = 0; y <= SCREEN_HEIGHT; y += bH)
4 for (int x = 0; x <= SCREEN_WIDTH; x += bW)
5 ApplySurface(x, y, background, renderer);

 

用 SDL2 显示一张图片

发表于 2016-06-05 | 更新于 2018-08-09

来源:

http://adolfans.github.io/sdltutorialcn/ (中文教程)

http://www.willusher.io/pages/sdl2/ (英文教程)

环境:SDL2 + VC++2015

下面的代码将打开一个窗口显示hello.bmp


 1 #include <iostream>
2 #include <SDL.h>
3
4 int main(int argc, char* argv)
5 {
6 //初始化SDL
7 if (SDL_Init(SDL_INIT_VIDEO) != 0)
8 {
9 std::cout << “SDL_Init Error: “ << SDL_GetError() << std::endl;
10 return 1;
11 }
12
13 //创建窗口
14 SDL_Window
win = nullptr;
15 win = SDL_CreateWindow(“Hello World!“,
16 SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
17 640, 480, SDL_WINDOW_SHOWN);
18 if (win == nullptr)
19 {
20 std::cout << SDL_GetError() << std::endl;
21 return 1;
22 }
23
24 //创建渲染器
25 SDL_Renderer ren = nullptr;
26 ren = SDL_CreateRenderer(win, -1,
27 SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
28 if (ren == nullptr)
29 {
30 std::cout << SDL_GetError() << std::endl;
31 return 1;
32 }
33
34 //创建表面
35 SDL_Surface
bmp = nullptr;
36 bmp = SDL_LoadBMP(“hello.bmp“);
37 if (bmp == nullptr) {
38 std::cout << SDL_GetError() << std::endl;
39 return 1;
40 }
41
42 //创建材质
43 SDL_Texture *tex = nullptr;
44 tex = SDL_CreateTextureFromSurface(ren, bmp);
45 SDL_FreeSurface(bmp);
46
47 //清空渲染器
48 SDL_RenderClear(ren);
49 //将材质复制到渲染器
50 SDL_RenderCopy(ren, tex, NULL, NULL);
51 //呈现渲染器
52 SDL_RenderPresent(ren);
53 //窗口延时
54 SDL_Delay(2000);
55
56 //释放资源
57 SDL_DestroyTexture(tex);
58 SDL_DestroyRenderer(ren);
59 SDL_DestroyWindow(win);
60 //退出SDL
61 SDL_Quit();
62
63 return 0;
64 }

 

VPS 安全措施(CentOS 6)

发表于 2016-06-05 | 更新于 2018-08-09

新到手一台VPS,要做的第一件事大概是做好安全措施。

下面针对CentOS 6随便写点,我目前做的几步是:

  1. 修改root密码
  2. SSH-key登录
  3. 配置iptable
  4. 安装fail2ban

1.修改root密码

登录到VPS,键入 passwd 即可修改root密码,注意输入内容不会以星号呈现。

2.采用SSH-key登录

采用密钥登录的好处就是如果有人知道你的root密码了,但他没有对应的密钥文件,那么他就不能通过SSH登录到VPS。而这个密钥文件只存在在你自己的电脑上,除非你硬盘被盗或者被入侵了。相应的教程实在太多了,这里简略说下:


1 //服务器端(生成密钥对)
2 ssh-keygen -t rsa //生成密钥,按照提示操作
3 //将root/.ssh目录中的id_rsa和id_rsa.pub下载到本地
4 cd /root/.ssh //更改工作目录到/root/.ssh
5 mv id_rsa.pub authorized_keys //将id_rsa.pub重命名为authorized_keys
6 chmod 600 authorized_keys //给authorized_keys设置600权限
7 vi /etc/ssh/sshd_config //编辑SSHD配置文件
8 //去掉RSAAuthentication和PubkeyAuthentication两行前面的#
9 /etc/init.d/sshd restart //重启SSHD服



1 //本地端(载入私钥)
2 打开puttygen.exe,载入密钥(id_rsa文件,无后缀),输入在SSH中设置的密钥密码,最后保存私钥(Putty适用的类型,后缀为ppk)。
3 打开putty.exe,找到连接(Connection)-SSH-认证(Auth),找到“认证私钥文件”一栏(Private key for authentication),点击浏览(Browse),载入刚才保存的ppk文件,应该可以顺利登陆了。



1 //服务器端(关闭密码登录)
2 vi /etc/ssh/sshd_config //编辑SSHD配置文件
3 //找到PasswordAuthentication后面的yes改成no,保存
4 /etc/init.d/sshd restart //重启SSHD服

到此,VPS密钥登录配置完成。

3.配置iptables

iptables 是一个配置 Linux 内核 防火墙 的命令行工具,是 netfilter 项目的一部分。术语 iptables 也经常代指该内核级防火墙。iptables 可以直接配置,也可以通过许多 前端 和 图形界面 配置。iptables 用于 ipv4,ip6tables 用于 ipv6。

Archlinux Wiki 中的 iptables 条目

 iptables研究起来会耗费大量时间,有兴趣的话不妨移步:Iptables 指南 1.1.19

下面粘贴一下自己的配置:


*filter
:INPUT ACCEPT [
0:0]
:FORWARD ACCEPT [
0:0]
:OUTPUT ACCEPT [
0:0]

# 开放本地和Ping
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -j ACCEPT

# 保持当前SSH连接
-A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT

# 控制端口
# HTTP (建站才会用到)
#
-A INPUT -p tcp –dport 80 -j ACCEPT
# nginx (建站才会用到)
#
-A INPUT -p tcp –dport 8384 -j ACCEPT
# SSH (自行修改)
-A INPUT -p tcp –dport $(SSH)-j ACCEPT
# SS (自行修改)
-A INPUT -p tcp –dport $(SS)-j ACCEPT

#拒绝其它
-A INPUT -p icmp -j REJECT –reject-with icmp-port-unreachable
-A INPUT -j REJECT –reject-with icmp-port-unreachable
-A FORWARD -j REJECT –reject-with icmp-port-unreachable

#开放出口
-A OUTPUT -j ACCEPT

COMMIT

 4.fail2ban

字面上理解,就是“登录失败了就把你ban掉”,可以防范某些不怀好意的人暴力登录你的VPS。

可参考:centos下fail2ban安装与配置详解

VPS 入坑之路

发表于 2016-06-04 | 更新于 2018-08-09

一、入坑动机:

以前一直的翻墙服务也被请喝茶了,仅限企业客户使用。于是想到租用一个VPS,搭个梯子。

 

二、入坑之路:

1.购买

想起在G+看见有人推荐搬瓦工性价比很高,去了解了一下,最低配置19.99刀一年,折合人民币也就十块一个月的样子,果断入之。

 

2.SS

以前在虚拟机稍微接触过linux,比如ubuntu和fedora,然而都是在图形界面瞎搞。这次终于有机会在终端操作了。各种命令上手确实不容易,只会cd,ls…突然发现控制面板有一键搭建SS,后来又放弃了敲命令…有一天心血来潮,决定自己搭建SS-libev(据说内存占用低,性能优秀),于是Install new OS,重装系统。参考各种教程后,搭建成功。

 

 

意外地发现VPS可以申请v6地址,重点是校园网v6无限流量,于是又想搭个v4/v6双栈服务器,让SS同时支持v4/v6。这里走了点弯路,不知道为什么去搞了一下Squid,徒劳无功。最后发现SS自带监听v6流量…

3.防火墙

好景不长。不久后有一天不能翻墙了,登陆面板,收到来自搬瓦工的Warning,如图。

 

 

Mass Mailing?简直匪夷所思。一开始啥也不管,直接点unsuspend,果断重装系统。心想总没问题了吧。当晚凌晨,再次被暂停服务。

 

 

 

一年只能解封三次,只剩一次机会了…20刀即将打水漂。这次没有立刻解封,Google后才知道VPS被肉鸡了,必须配置防火墙。然后又开始了新一轮折腾。首先改掉root密码,然后关闭密码登录,只允许密钥登录。然后配置iptable,封掉所有无用端口。最后加入fail2ban,世界终于清静了。

 

三、各种玩法

  下面是我的概要记录:

系统级:

Iptable + sshkey + fail2ban 搭建防火墙

Ps -A + top 查看进程

Iftop + netstat实时查看网络流量

应用级:

 

Shadowsocks-libev 翻墙

Aria2实现离线下载

Aria2-webui实现aria2图形化

Nginx开放80/8384搭建下载服务器

Dot.tk获得免费域名

搭建FTP 利用SSHD服务SFTP(Filezilla+SSH端口+密钥)

搞个面板?Vesta ajenti

Wordpress搭建博客

startSSL获得SSL证书实现HTTPS连接

Postfix 邮件系统

 

四、后记

VPS真是个好东西。以后再补充下各种心得。

PS:番羽土蔷全成了FQ…也是醉

 

Hello World!

发表于 2016-06-04 | 更新于 2018-08-09

2016-06-04,博客首文。

Joxon

15 日志
GitHub
© 2019 Joxon
由 Hexo 强力驱动 v3.7.1
|
主题 – NexT.Muse v6.4.0