通知设置 新通知
shell 工具箱 总结平时用到的一些shell函数 方便复用
回复问答 • jintianfree 回复了问题 • 1 人关注 • 6 个回复 • 29 次浏览 • 2019-10-25 13:38
nginx access log 很多转义字符串 类似\x22text\x22:\x22\xE7\x83\x98\x\xAE\x22 怎么转回来
问答 • jintianfree 发表了文章 • 0 个评论 • 71 次浏览 • 2019-10-25 12:03
python2测试OK
print (" {\x0A \x22campaign\x22: \x22c181518671956.820106\x22,\x0A \x22platform\x22:1,\x0A \x22price\x22:0,\x0A \x22materials\x22:[{\x22file_type\x22:1,\x22img_url\x22:\x22http://staging.trylemonade.com ... 1.jpg\x22}],\x0A \x22content\x22: \x22\xE6\xB8\xAC\xE8\xA9\xA6submit\x22,\x0A \x22tags\x22: [{\x22tag_type\x22:\x22#\x22,\x22text\x22:\x22\xE7\x83\x98\xE7\x88\x90\xE5\x9C\xB0\xE5\x8D\x97\xE5\xB1\xB1\xE7\xA6\x8F\xE5\xBE\xB7\xE5\xAE\xAE\x22},{\x22tag_type\x22:\x22#\x22,\x22text\x22:\x22\xE6\x8B\x9C\xE6\x8B\x9C\xE6\x84\x9B\xE7\x94\xA8\xE9\x96\x8B\xE9\x81\x8B\xE6\x8B\x9B\xE8\xB2\xA1\xE5\x8C\x85\x22}],\x0A \x22influencer\x22:\x0A {\x22third_party_token\x22:\x22EAAXNnbIx0GoBAJ0n6pJO3o0M5buUaEnXOfyMXryuQdqRUGHPSlhUNZCZAdWHABqntpWf2cXZCMWbdLYSLF0POA9uUrZCQAGIVxMl983P20n247BQerZBnUvwRkujZCGa6monlNVj9tW6hZAam5zQZA6VqcoQT8ugTOvd1fBM09GQsgZDZD\x22,\x22fan_count\x22:1264,\x22third_party_id\x22:\x221389525994710539\x22,\x22third_party_type\x22:1,\x22user_avatar\x22:\x22https://scontent.xx.fbcdn.net/ ... B2DD4\x22,\x22user_name\x22:\x22\xE6\x84\x9B\xE6\xAD\xA3\xE5\xA6\xB9\x22}\x0A}".decode('string-escape'))
{
"campaign": "c181518671956.820106",
"platform": 1,
"price": 0,
"materials": [{
"file_type": 1,
"img_url": "http://www.baidu.com/media/upl ... ot%3B
}],
"content": "測試submit",
"tags": [{
"tag_type": "#",
"text": "烘爐地南山福德宮"
}, {
"tag_type": "#",
"text": "拜拜愛用開運招財包"
}],
"influencer": {
"third_party_token": "EAAXNnbIx0GoBAJ0n6pJO3o5buUaEnXOfyMXryuQdqRUGHPSlhUNZCZAdWHABqntpWf2cXZCMWbdLYSLF0POA9uUrZCQAGIVxMl983P20n247BQerZBnUvwRkujZCGa6monlNVj9tW6hZAam5zQZA6VqcoQT8ugTOvd1fBM09GQsgZDZD",
"fan_count": 1264,
"third_party_id": "13895294710539",
"third_party_type": 1,
"user_avatar": "https://scontent.xx.fbcdn.net/ ... ot%3B,
"user_name": "正妹"
}
} 查看全部
python2测试OK
print (" {\x0A \x22campaign\x22: \x22c181518671956.820106\x22,\x0A \x22platform\x22:1,\x0A \x22price\x22:0,\x0A \x22materials\x22:[{\x22file_type\x22:1,\x22img_url\x22:\x22http://staging.trylemonade.com ... 1.jpg\x22}],\x0A \x22content\x22: \x22\xE6\xB8\xAC\xE8\xA9\xA6submit\x22,\x0A \x22tags\x22: [{\x22tag_type\x22:\x22#\x22,\x22text\x22:\x22\xE7\x83\x98\xE7\x88\x90\xE5\x9C\xB0\xE5\x8D\x97\xE5\xB1\xB1\xE7\xA6\x8F\xE5\xBE\xB7\xE5\xAE\xAE\x22},{\x22tag_type\x22:\x22#\x22,\x22text\x22:\x22\xE6\x8B\x9C\xE6\x8B\x9C\xE6\x84\x9B\xE7\x94\xA8\xE9\x96\x8B\xE9\x81\x8B\xE6\x8B\x9B\xE8\xB2\xA1\xE5\x8C\x85\x22}],\x0A \x22influencer\x22:\x0A {\x22third_party_token\x22:\x22EAAXNnbIx0GoBAJ0n6pJO3o0M5buUaEnXOfyMXryuQdqRUGHPSlhUNZCZAdWHABqntpWf2cXZCMWbdLYSLF0POA9uUrZCQAGIVxMl983P20n247BQerZBnUvwRkujZCGa6monlNVj9tW6hZAam5zQZA6VqcoQT8ugTOvd1fBM09GQsgZDZD\x22,\x22fan_count\x22:1264,\x22third_party_id\x22:\x221389525994710539\x22,\x22third_party_type\x22:1,\x22user_avatar\x22:\x22https://scontent.xx.fbcdn.net/ ... B2DD4\x22,\x22user_name\x22:\x22\xE6\x84\x9B\xE6\xAD\xA3\xE5\xA6\xB9\x22}\x0A}".decode('string-escape'))
{
"campaign": "c181518671956.820106",
"platform": 1,
"price": 0,
"materials": [{
"file_type": 1,
"img_url": "http://www.baidu.com/media/upl ... ot%3B
}],
"content": "測試submit",
"tags": [{
"tag_type": "#",
"text": "烘爐地南山福德宮"
}, {
"tag_type": "#",
"text": "拜拜愛用開運招財包"
}],
"influencer": {
"third_party_token": "EAAXNnbIx0GoBAJ0n6pJO3o5buUaEnXOfyMXryuQdqRUGHPSlhUNZCZAdWHABqntpWf2cXZCMWbdLYSLF0POA9uUrZCQAGIVxMl983P20n247BQerZBnUvwRkujZCGa6monlNVj9tW6hZAam5zQZA6VqcoQT8ugTOvd1fBM09GQsgZDZD",
"fan_count": 1264,
"third_party_id": "13895294710539",
"third_party_type": 1,
"user_avatar": "https://scontent.xx.fbcdn.net/ ... ot%3B,
"user_name": "正妹"
}
}
wecenter 设置伪静态
博客 • blog 发表了文章 • 0 个评论 • 28 次浏览 • 2017-10-31 20:43
RewriteBase / 需不需要加看情况 如果不生效 则加上
我的网站托管到000webhost上 需要添加这一行
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
2、网站后台管理 站点功能配置处
选择开启伪静态
在自定义路由处填写
/article/(:any)===/article_(:any).html
/question/(:any)===/question_(:any).html
3、观察效果
随便打开一个问题或文章 地址已经变了
/question/20 已经变成了 /question_20.html 查看全部
RewriteBase / 需不需要加看情况 如果不生效 则加上
我的网站托管到000webhost上 需要添加这一行
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
2、网站后台管理 站点功能配置处
选择开启伪静态
在自定义路由处填写
/article/(:any)===/article_(:any).html
/question/(:any)===/question_(:any).html
3、观察效果
随便打开一个问题或文章 地址已经变了
/question/20 已经变成了 /question_20.html
VirtualBox中的Ubuntu没有权限访问通过VirtualBox设置的共享文件夹
回复问答 • wenda 回复了问题 • 1 人关注 • 1 个回复 • 33 次浏览 • 2017-10-20 11:20
wecenter 使用highlight.js 高亮代码
博客 • blog 发表了文章 • 0 个评论 • 69 次浏览 • 2017-10-13 00:54
views/default/global/header_meta.tpl
在<head></head>中加入
<pre><code class="html">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</code></pre>
2、使用
<pre><code class="html">
<pre><code class="html">
放置代码
</code></pre>
</code></pre>
3、highlight.js详细教程
<a href="https://highlightjs.org/" rel="nofollow" target="_blank">https://highlightjs.org/</a>
===================
使用bbcode 代替 pre code
1、编辑网站
修改system/Services/BBCode.php
org标注的是原始代码 把这两行替换成org下面的一行
<pre><code class="php">
private function _code_callback($match)
{
//return "<pre>" . str_replace('[', '<span>[</span>', $match[1]) . "</pre>"; // org
return "<pre><code $match[1]>$match[2]</code></pre>";
}
public function __construct()
{
// Replace [code]...[//code] with <pre><code>...</code></pre>
// $this->bbcode_table["/\[code\](.*?)\[\/code\]/is"] = '_code_callback'; // org
$this->bbcode_table["/\[code(.*?)\](.*?)\[\/code\]/is"] = '_code_callback';
}
<code></pre>
2、使用
[code class="html"]
放置代码
注意//code 要写成/code
我这里避免真的当代码转了 所以放置了两个//
[//code]
TODO:
20191025 网站重新部署好 bbcode没生效 还没时间调查 查看全部
views/default/global/header_meta.tpl
在<head></head>中加入
<pre><code class="html">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</code></pre>
2、使用
<pre><code class="html">
<pre><code class="html">
放置代码
</code></pre>
</code></pre>
3、highlight.js详细教程
<a href="https://highlightjs.org/" rel="nofollow" target="_blank">https://highlightjs.org/</a>
===================
使用bbcode 代替 pre code
1、编辑网站
修改system/Services/BBCode.php
org标注的是原始代码 把这两行替换成org下面的一行
<pre><code class="php">
private function _code_callback($match)
{
//return "<pre>" . str_replace('[', '<span>[</span>', $match[1]) . "</pre>"; // org
return "<pre><code $match[1]>$match[2]</code></pre>";
}
public function __construct()
{
// Replace [code]...[//code] with <pre><code>...</code></pre>
// $this->bbcode_table["/\[code\](.*?)\[\/code\]/is"] = '_code_callback'; // org
$this->bbcode_table["/\[code(.*?)\](.*?)\[\/code\]/is"] = '_code_callback';
}
<code></pre>
2、使用
[code class="html"]
放置代码
注意//code 要写成/code
我这里避免真的当代码转了 所以放置了两个//
[//code]
TODO:
20191025 网站重新部署好 bbcode没生效 还没时间调查
一个简单的app server搭建 - 未完
博客 • blog 发表了文章 • 0 个评论 • 104 次浏览 • 2017-10-11 22:17
前期
初始阶段,我们会把服务搭成下面这个样子。用户通过域名走http协议,访问我们的服务,前端使用nginx处理http请求,数据转发到后端的app server处理。
选择http协议作为客户端和服务端交互的协议,当然也可以使用其他协议(比如邮件客户端和服务器之间采用smtp/pop3协议),或者自定义网络协议(比如QQ客户端和服务器之间是腾讯自己定义的协议),http协议简单、无状态,请求-响应-结束,下一次请求和响应直接不存在关系。
选择nginx作为http server。为什么要使用nginx,而不是直接让app server接受请求?比如这样:
1、如果app server直接接收请求,那么app server需要负责解析http协议,然后拿到数据,再做自己的业务处理。nginx可以帮我们处理http层的东西,把一些信息(比如客户端IP地址)和应用数据转给app server,这样app server只需要负责处理业务数据就好了。
2、nginx可以实现简单的负载均衡、热备的功能,app server不需要关心和开发这些功能,专注处理业务逻辑。
接下来,定一下nginx和app server的数据传输格式和方式:
有几个选择:
1、cgi (cgi只能通过标准输入输出与本地的nginx通信)
2、fastcgi
3、google protobuf (通过tcp协议传输protobuf格式数据)
4、自定义协议
5、...
我选择fastcgi协议,简单、通用,nginx直接支持。fastcgi与nginx通过tcp通信,两者可以处于不同的物理机上。怎么配置我这里就不介绍了。
server开发
以下server框架推荐大家了解:
1、epoll
2、muduo
3、spserver
4、boost asio
这里使用简单spawn-fcgi + libfcgi 写一个简单的app server。
libfcgi
源码地址:https://github.com/LuaDist/fcg ... bfcgi
这里不多说,这个lib库可以帮你解析nginx传过来的数据。
spawn-fcgi
源码地址: https://github.com/lighttpd/spawn-fcgi
spawn-fcgi很简单。他负责建立server端的tcp socket,然后启动子进程,将socket dup到标准输入上。这样子进程accept 标准输入,接受新连接,接收数据,响应。
下面是代码事例,子进程调用FCGI_Accept,在标准输入上接收一个新链接,然后向链接写入数据作为响应。
#include
#include
#include
int main()
{
int count = 0;
while(FCGI_Accept() >= 0) {
// 这个可以通过FCGI提供的接口获取请求带来的数据
FCGI_printf("Content-type: text/html\r\n"
"\r\n"
""
"FastCGI Hello!"
"Request number %d running on host%s "
"Process ID: %d\n", ++count, getenv("SERVER_NAME"), getpid());
}
return 0;
}
编译
g++ childfcgi.c -o child -lfcgi
配置nginx的upstream
upstream backend {
server 127.0.0.1:8002;
keepalive 600;
}
location / {
fastcgi_pass backend;
fastcgi_keep_conn on;
fastcgi_index index.cgi;
include fastcgi_params;
}
运行
/usr/local/nginx/sbin/spawn-fcgi -a 127.0.0.1 -p 8002 -C 25 -f /usr/local/nginx/cgibin/child
这样spawn-fcgi和编译的小程序组成了一个app server与nginx配合就可以处理请求和响应了。
再来回顾下这个框架图:
进阶
随着业务发展,请求数变多,你会发现服务压力越来越大。是时候优化下server了。
http://blog.csdn.net/wzhwho/ar ... 69620 查看全部
前期
初始阶段,我们会把服务搭成下面这个样子。用户通过域名走http协议,访问我们的服务,前端使用nginx处理http请求,数据转发到后端的app server处理。
选择http协议作为客户端和服务端交互的协议,当然也可以使用其他协议(比如邮件客户端和服务器之间采用smtp/pop3协议),或者自定义网络协议(比如QQ客户端和服务器之间是腾讯自己定义的协议),http协议简单、无状态,请求-响应-结束,下一次请求和响应直接不存在关系。
选择nginx作为http server。为什么要使用nginx,而不是直接让app server接受请求?比如这样:
1、如果app server直接接收请求,那么app server需要负责解析http协议,然后拿到数据,再做自己的业务处理。nginx可以帮我们处理http层的东西,把一些信息(比如客户端IP地址)和应用数据转给app server,这样app server只需要负责处理业务数据就好了。
2、nginx可以实现简单的负载均衡、热备的功能,app server不需要关心和开发这些功能,专注处理业务逻辑。
接下来,定一下nginx和app server的数据传输格式和方式:
有几个选择:
1、cgi (cgi只能通过标准输入输出与本地的nginx通信)
2、fastcgi
3、google protobuf (通过tcp协议传输protobuf格式数据)
4、自定义协议
5、...
我选择fastcgi协议,简单、通用,nginx直接支持。fastcgi与nginx通过tcp通信,两者可以处于不同的物理机上。怎么配置我这里就不介绍了。
server开发
以下server框架推荐大家了解:
1、epoll
2、muduo
3、spserver
4、boost asio
这里使用简单spawn-fcgi + libfcgi 写一个简单的app server。
libfcgi
源码地址:https://github.com/LuaDist/fcg ... bfcgi
这里不多说,这个lib库可以帮你解析nginx传过来的数据。
spawn-fcgi
源码地址: https://github.com/lighttpd/spawn-fcgi
spawn-fcgi很简单。他负责建立server端的tcp socket,然后启动子进程,将socket dup到标准输入上。这样子进程accept 标准输入,接受新连接,接收数据,响应。
下面是代码事例,子进程调用FCGI_Accept,在标准输入上接收一个新链接,然后向链接写入数据作为响应。
#include
#include
#include
int main()
{
int count = 0;
while(FCGI_Accept() >= 0) {
// 这个可以通过FCGI提供的接口获取请求带来的数据
FCGI_printf("Content-type: text/html\r\n"
"\r\n"
""
"FastCGI Hello!"
"Request number %d running on host%s "
"Process ID: %d\n", ++count, getenv("SERVER_NAME"), getpid());
}
return 0;
}
编译
g++ childfcgi.c -o child -lfcgi
配置nginx的upstream
upstream backend {
server 127.0.0.1:8002;
keepalive 600;
}
location / {
fastcgi_pass backend;
fastcgi_keep_conn on;
fastcgi_index index.cgi;
include fastcgi_params;
}
运行
/usr/local/nginx/sbin/spawn-fcgi -a 127.0.0.1 -p 8002 -C 25 -f /usr/local/nginx/cgibin/child
这样spawn-fcgi和编译的小程序组成了一个app server与nginx配合就可以处理请求和响应了。
再来回顾下这个框架图:
进阶
随着业务发展,请求数变多,你会发现服务压力越来越大。是时候优化下server了。
http://blog.csdn.net/wzhwho/ar ... 69620
内网服务器 通过ssh 端口转发 对外提供服务
博客 • blog 发表了文章 • 0 个评论 • 47 次浏览 • 2017-10-11 22:14
需要一个外网服务器做转发,其实如果有了外网服务器,还把服务配置在内网干啥。
===============================================================
VPS
vps的ssh配置文件,/etc/ssh/sshd_config 文件 需要设置:
GatewayPorts yes
X11Forwarding yes
重启sshd
===============================================================
内网服务器:
autossh -M 5678 -CNfR 9999:127.0.0.1:80 root@199.83.88.179
将127.0.0.1的80端口 反向映射到 199.83.88.179的9999端口上
这样通过外网访问199.83.88.179:9999时 就是访问的127.0.0.1:80
===============================================================
运行autossh时 每次需要输入密码 可以生成秘钥 利用秘钥登陆
#### 客户端
生成秘钥公钥 ssh-keygen -t rsa
将公钥拷到Server scp /root/.ssh/id_rsa.pub root@199.83.88.179:/root/.ssh
#### VPS上
创建authorized_keys2文件
touch /root/.ssh/authorized_keys2 (如果已经存在这个文件, 跳过这条)
追加公钥到authorized_keys2中
cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys2
(将id_rsa.pub的内容追加到 authorized_keys2 中)
#### 客户端上再次运行
autossh -M 5678 -CNfR 9999:192.168.1.11:80 root@199.83.88.179
不需要使用用户名密码了
===============================================================
可以把 9999:192.168.1.11:80 换成自己的IP和端口 尝试下
ssh -CNfR 9999:127.0.0.1:22 root@199.83.88.179
199.83.88.179
@***
ssh -p 9999 root@localhost
ssh -f -N -R 10000:localhost:22 username@主控端ip
参考:
本地转发
远程转发
http://blog.chinaunix.net/uid- ... .html
正向连接
反向连接
代理
http://blog.csdn.net/linsanhua ... 60369 查看全部
需要一个外网服务器做转发,其实如果有了外网服务器,还把服务配置在内网干啥。
===============================================================
VPS
vps的ssh配置文件,/etc/ssh/sshd_config 文件 需要设置:
GatewayPorts yes
X11Forwarding yes
重启sshd
===============================================================
内网服务器:
autossh -M 5678 -CNfR 9999:127.0.0.1:80 root@199.83.88.179
将127.0.0.1的80端口 反向映射到 199.83.88.179的9999端口上
这样通过外网访问199.83.88.179:9999时 就是访问的127.0.0.1:80
===============================================================
运行autossh时 每次需要输入密码 可以生成秘钥 利用秘钥登陆
#### 客户端
生成秘钥公钥 ssh-keygen -t rsa
将公钥拷到Server scp /root/.ssh/id_rsa.pub root@199.83.88.179:/root/.ssh
#### VPS上
创建authorized_keys2文件
touch /root/.ssh/authorized_keys2 (如果已经存在这个文件, 跳过这条)
追加公钥到authorized_keys2中
cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys2
(将id_rsa.pub的内容追加到 authorized_keys2 中)
#### 客户端上再次运行
autossh -M 5678 -CNfR 9999:192.168.1.11:80 root@199.83.88.179
不需要使用用户名密码了
===============================================================
可以把 9999:192.168.1.11:80 换成自己的IP和端口 尝试下
ssh -CNfR 9999:127.0.0.1:22 root@199.83.88.179
199.83.88.179
@***
ssh -p 9999 root@localhost
ssh -f -N -R 10000:localhost:22 username@主控端ip
参考:
本地转发
远程转发
http://blog.chinaunix.net/uid- ... .html
正向连接
反向连接
代理
http://blog.csdn.net/linsanhua ... 60369
给libpcap增加一个新的捕包方法
博客 • blog 发表了文章 • 0 个评论 • 46 次浏览 • 2017-10-11 22:13
为libpcap添加一个捕包方法非常简单,下面代码先实现捕获内存中一个固定包的功能,保证能够工作后,再去支持专有驱动或者专用网卡的收包。以下所涉及的libpcap代码和tcpdump代码,版本分别为libpcap-1.7.2,tcpdump-4.1.1。
首先添加两个文件,编写收包的代码,可以参考的代码还是挺多的,比如pcap-snoop.c、pcap-can-linux.c等。
pcap-ring.h
pcap_t *ring_create(const char *device, char *ebuf, int *is_ours);
int ring_findalldevs(pcap_if_t **alldevsp, char *errbuf);
pcap-ring.c
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include /* optionally get BSD define */
#include
#ifdef HAVE_OS_PROTO_H
# include "os-proto.h"
#endif
#include "pcap-int.h"
#include "errno.h"
struct pcap_ring {
int pad;
};
/*
* 192.168.19.105 -> 202.106.4.151
* DNS
* Name: offlintab.firefoxchina.cn
* Type: A
* Class: IN
*/
char peer0_0[] = {
0x8c,0x21,0x0a,0x6d,0x72,0x58,0x00,0x26,0xc7,0x35,0x2f,0x58,0x08,0x00,0x45,0x00
,0x00,0x47,0x72,0x51,0x00,0x00,0x40,0x11,0x3b,0x42,0xc0,0xa8,0x13,0x69,0xca,0x6a
,0x2e,0x97,0xe5,0x30,0x00,0x35,0x00,0x33,0x5a,0x2e,0x67,0xcb,0x01,0x00,0x00,0x01
,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x6f,0x66,0x66,0x6c,0x69,0x6e,0x74,0x61,0x62
,0x0c,0x66,0x69,0x72,0x65,0x66,0x6f,0x78,0x63,0x68,0x69,0x6e,0x61,0x02,0x63,0x6e
,0x00,0x00,0x01,0x00,0x01
};
static int pcap_read_ring(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
int wirelen = sizeof(peer0_0);
int caplen = wirelen;
if(p->break_loop) {
p->break_loop = 0;
/* can release resource here */
return -2; /* must be -2 */
}
if (caplen > p->snapshot) {
caplen = p->snapshot;
}
memcpy(p->buffer, peer0_0, caplen);
if (bpf_filter(p->fcode.bf_insns, p->buffer, wirelen, caplen)) {
struct pcap_pkthdr h;
gettimeofday(&h.ts, NULL);
h.len = wirelen;
h.caplen = caplen;
(*callback)(user, &h, p->buffer);
return 1;
}
return 0;
}
static int pcap_stats_ring(pcap_t *p, struct pcap_stat *ps)
{
/* not yet implemented */
ps->ps_recv = 0; /* number of packets received */
ps->ps_drop = 0; /* number of packets dropped */
ps->ps_ifdrop = 0; /* drops by interface -- only supported on some platforms */
return (0);
}
static int pcap_getnonblock_ring(pcap_t *p, char *errbuf)
{
return (0);
}
static int pcap_setnonblock_ring(pcap_t *p, int nonblock, char *errbuf)
{
return (0);
}
static int pcap_inject_ring(pcap_t *p, const void *buf _U_, size_t size _U_)
{
strlcpy(p->errbuf, "Sending packets isn't supported", PCAP_ERRBUF_SIZE);
return (-1);
}
int pcap_activate_ring(pcap_t *handle)
{
handle->bufsize = 2048;
handle->linktype = DLT_EN10MB;
handle->selectable_fd = -1;
handle->read_op = pcap_read_ring;
handle->stats_op = pcap_stats_ring;
handle->inject_op = pcap_inject_ring;
handle->setfilter_op = install_bpf_program;
handle->setdirection_op = NULL;
handle->set_datalink_op = NULL;
handle->getnonblock_op = pcap_getnonblock_fd; //pcap_getnonblock_ring;
handle->setnonblock_op = pcap_setnonblock_fd;//pcap_setnonblock_ring;
handle->buffer = (u_char *)malloc(handle->bufsize);
if (handle->buffer == NULL) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't allocate dump buffer: %s", pcap_strerror(errno));
pcap_cleanup_live_common(handle);
return (PCAP_ERROR);
}
return 0;
}
pcap_t *ring_create(const char *device, char *ebuf, int *is_ours)
{
pcap_t *p;
if(strncmp(device, "ring", 4) != 0) {
*is_ours = 0;
return NULL;
}
*is_ours = 1;
p = pcap_create_common(device, ebuf, sizeof(struct pcap_ring));
if (p == NULL) {
return (NULL);
}
p->activate_op = pcap_activate_ring;
return (p);
}
int ring_findalldevs(pcap_if_t **alldevsp, char *errbuf)
{
return (0);
}
修改pcap.c,支持新的收包方式。
pcap.c
#include "pcap-ring.h"
struct capture_source_type {
int (*findalldevs_op)(pcap_if_t **, char *);
pcap_t *(*create_op)(const char *, char *, int *);
} capture_source_types[] = {
#ifdef PCAP_SUPPORT_DBUS
... ...
{ dbus_findalldevs, dbus_create },
#endif
{ ring_findalldevs, ring_create }, /* new !!! */
{ NULL, NULL }
};
修改 Makefile.in ,将新添加的文件编译进去。
PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @BT_MONITOR_SRC@ \
@CAN_SRC@ @NETFILTER_SRC@ @CANUSB_SRC@ @DBUS_SRC@ pcap-ring.c
接下来可以编译了:
./configure
make
可以看到libpcap.a了。
接下编译tcpdump-4.1.1
./configure
make
运行:
[root@localhost tcpdump-4.1.1]# ./tcpdump -i ring1 -c 2
listening on ring1, link-type EN10MB (Ethernet), capture size 65535 bytes
02:17:45.465535 IP localhost.58672 > dialdns.bta.net.cn.domain: 26571+ A? offlintab.firefoxchina.cn. (43)
02:17:45.485310 IP localhost.58672 > dialdns.bta.net.cn.domain: 26571+ A? offlintab.firefoxchina.cn. (43)
2 packets captured
0 packets received by filter
0 packets dropped by kernel
可以看到,tcpdump能拿到包并解析了。 查看全部
为libpcap添加一个捕包方法非常简单,下面代码先实现捕获内存中一个固定包的功能,保证能够工作后,再去支持专有驱动或者专用网卡的收包。以下所涉及的libpcap代码和tcpdump代码,版本分别为libpcap-1.7.2,tcpdump-4.1.1。
首先添加两个文件,编写收包的代码,可以参考的代码还是挺多的,比如pcap-snoop.c、pcap-can-linux.c等。
pcap-ring.h
pcap_t *ring_create(const char *device, char *ebuf, int *is_ours);
int ring_findalldevs(pcap_if_t **alldevsp, char *errbuf);
pcap-ring.c
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include /* optionally get BSD define */
#include
#ifdef HAVE_OS_PROTO_H
# include "os-proto.h"
#endif
#include "pcap-int.h"
#include "errno.h"
struct pcap_ring {
int pad;
};
/*
* 192.168.19.105 -> 202.106.4.151
* DNS
* Name: offlintab.firefoxchina.cn
* Type: A
* Class: IN
*/
char peer0_0[] = {
0x8c,0x21,0x0a,0x6d,0x72,0x58,0x00,0x26,0xc7,0x35,0x2f,0x58,0x08,0x00,0x45,0x00
,0x00,0x47,0x72,0x51,0x00,0x00,0x40,0x11,0x3b,0x42,0xc0,0xa8,0x13,0x69,0xca,0x6a
,0x2e,0x97,0xe5,0x30,0x00,0x35,0x00,0x33,0x5a,0x2e,0x67,0xcb,0x01,0x00,0x00,0x01
,0x00,0x00,0x00,0x00,0x00,0x00,0x09,0x6f,0x66,0x66,0x6c,0x69,0x6e,0x74,0x61,0x62
,0x0c,0x66,0x69,0x72,0x65,0x66,0x6f,0x78,0x63,0x68,0x69,0x6e,0x61,0x02,0x63,0x6e
,0x00,0x00,0x01,0x00,0x01
};
static int pcap_read_ring(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
{
int wirelen = sizeof(peer0_0);
int caplen = wirelen;
if(p->break_loop) {
p->break_loop = 0;
/* can release resource here */
return -2; /* must be -2 */
}
if (caplen > p->snapshot) {
caplen = p->snapshot;
}
memcpy(p->buffer, peer0_0, caplen);
if (bpf_filter(p->fcode.bf_insns, p->buffer, wirelen, caplen)) {
struct pcap_pkthdr h;
gettimeofday(&h.ts, NULL);
h.len = wirelen;
h.caplen = caplen;
(*callback)(user, &h, p->buffer);
return 1;
}
return 0;
}
static int pcap_stats_ring(pcap_t *p, struct pcap_stat *ps)
{
/* not yet implemented */
ps->ps_recv = 0; /* number of packets received */
ps->ps_drop = 0; /* number of packets dropped */
ps->ps_ifdrop = 0; /* drops by interface -- only supported on some platforms */
return (0);
}
static int pcap_getnonblock_ring(pcap_t *p, char *errbuf)
{
return (0);
}
static int pcap_setnonblock_ring(pcap_t *p, int nonblock, char *errbuf)
{
return (0);
}
static int pcap_inject_ring(pcap_t *p, const void *buf _U_, size_t size _U_)
{
strlcpy(p->errbuf, "Sending packets isn't supported", PCAP_ERRBUF_SIZE);
return (-1);
}
int pcap_activate_ring(pcap_t *handle)
{
handle->bufsize = 2048;
handle->linktype = DLT_EN10MB;
handle->selectable_fd = -1;
handle->read_op = pcap_read_ring;
handle->stats_op = pcap_stats_ring;
handle->inject_op = pcap_inject_ring;
handle->setfilter_op = install_bpf_program;
handle->setdirection_op = NULL;
handle->set_datalink_op = NULL;
handle->getnonblock_op = pcap_getnonblock_fd; //pcap_getnonblock_ring;
handle->setnonblock_op = pcap_setnonblock_fd;//pcap_setnonblock_ring;
handle->buffer = (u_char *)malloc(handle->bufsize);
if (handle->buffer == NULL) {
snprintf(handle->errbuf, PCAP_ERRBUF_SIZE,
"Can't allocate dump buffer: %s", pcap_strerror(errno));
pcap_cleanup_live_common(handle);
return (PCAP_ERROR);
}
return 0;
}
pcap_t *ring_create(const char *device, char *ebuf, int *is_ours)
{
pcap_t *p;
if(strncmp(device, "ring", 4) != 0) {
*is_ours = 0;
return NULL;
}
*is_ours = 1;
p = pcap_create_common(device, ebuf, sizeof(struct pcap_ring));
if (p == NULL) {
return (NULL);
}
p->activate_op = pcap_activate_ring;
return (p);
}
int ring_findalldevs(pcap_if_t **alldevsp, char *errbuf)
{
return (0);
}
修改pcap.c,支持新的收包方式。
pcap.c
#include "pcap-ring.h"
struct capture_source_type {
int (*findalldevs_op)(pcap_if_t **, char *);
pcap_t *(*create_op)(const char *, char *, int *);
} capture_source_types[] = {
#ifdef PCAP_SUPPORT_DBUS
... ...
{ dbus_findalldevs, dbus_create },
#endif
{ ring_findalldevs, ring_create }, /* new !!! */
{ NULL, NULL }
};
修改 Makefile.in ,将新添加的文件编译进去。
PSRC = pcap-@V_PCAP@.c @USB_SRC@ @BT_SRC@ @BT_MONITOR_SRC@ \
@CAN_SRC@ @NETFILTER_SRC@ @CANUSB_SRC@ @DBUS_SRC@ pcap-ring.c
接下来可以编译了:
./configure
make
可以看到libpcap.a了。
接下编译tcpdump-4.1.1
./configure
make
运行:
[root@localhost tcpdump-4.1.1]# ./tcpdump -i ring1 -c 2
listening on ring1, link-type EN10MB (Ethernet), capture size 65535 bytes
02:17:45.465535 IP localhost.58672 > dialdns.bta.net.cn.domain: 26571+ A? offlintab.firefoxchina.cn. (43)
02:17:45.485310 IP localhost.58672 > dialdns.bta.net.cn.domain: 26571+ A? offlintab.firefoxchina.cn. (43)
2 packets captured
0 packets received by filter
0 packets dropped by kernel
可以看到,tcpdump能拿到包并解析了。
Docker基本安装与使用
博客 • blog 发表了文章 • 0 个评论 • 32 次浏览 • 2017-10-11 22:12
以下操作基于ubuntu 14.04 desktop版本,Docker 版本为1.0.1。其他版本的可能存在一些差异,读者请酌情参考。记录的同时也把出现的错误一同记录下来了。注意以下操作都使用了sudo进行了权限提升,记录中没有体现出来。
安装
$ apt-get install docker.io
E: Failed to fetch http://cn.archive.ubuntu.com/u ... 4.deb Size mismatch
E: Failed to fetch http://cn.archive.ubuntu.com/u ... l.deb Size mismatch
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
出错了,错误提示里面提示了怎么处理,按照提示做。
apt-get update
apt-get install docker.io --fix-missing
OK,安装成功了 。
基本操作
查看基本信息
service docker.io status
docker.io start/running, process 9220
docker -v
Docker version 1.0.1, build 990021a
docker images
没东西
获取image
想找符合自己要求的镜像可以在hub.docker.com找,比如找一个安装好http server的,找一个具备开发环境的。一般会找到符合自己需求的,这样就不需要自己搭建环境了。下面笔者下载安装了ubuntu 14.04.3的image。
docker search ubuntu
docker pull ubuntu:14.04.3
使用下面的命令可以看到系统里们已经存在的镜像
docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu 14.04 91e54dfb1179 5 weeks ago 188.4 MB
运行容器
docker run -i -t ubuntu:14.04.3 /bin/bash
退出容器
exit
提交镜像
注意:退出容器后,之前所有操作都不会保存,要保存需要在退出之前,使用commit命令再生成一个image。下面命令先查看了当前运行着的容器,然后将当前容器的状态保存为一个新镜像。保存后就可以退出了,下次启动容器使用新的镜像,上次的操作就会保留着,这样每次你做了修改,如果需要保存,就要提交一个新的镜像。
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cc6c51bbfff6 ubuntu:14.04 /bin/bash 3 minutes ago Up 3 minutes nostalgic_nobel
docker commit cc6c51bbfff6 ubuntu:14.04+
573049725ed15eaffe3fd42be6ec995200da9ea3e201fe7cd3e21628fd588fef
容器内安装ssh服务
启动进入容器后,安装openssh-server,然后修改/etc/ssh/sshd_config文件,修改内容见下面。然后提交当前镜像,保存操作。
apt-get install openssh-server
PermitRootLogin yes
UsePAM no
docker commit cc6c51bbfff6 ubuntu:14.04+openssh-server
接下来退出原来的容器,使用新的镜像启动容器,并做好端口映射。
docker run -i -t -p 50001:22 ubuntu:14.04+openssh-server /bin/bash
/usr/sbin/sshd
此时你另开一个终端,就可以使用ssh客户端登录容器进行操作了
ssh 127.0.0.1 -p 50001
镜像的导出与导入
docker save ubuntu:14.04+openssh-server >/home/andrew/ubuntu.tar
docker load <ubuntu.tar
挂载宿主目录
docker run -i -t -v /home/andrew:/opt 91e54dfb1179 /bin/bash
通过-v参数,冒号前为宿主机目录,必须为绝对路径,冒号后为镜像内挂载的路径。默认挂载的路径权限为读写。如果指定为只读可以用:ro
docker run -i -t -v /home/andrew:/opt:ro 91e54dfb1179 /bin/bash 查看全部
本文记录Dokcer的基本安装与使用,好记性不如烂博客,记录就是为了不忘记。
以下操作基于ubuntu 14.04 desktop版本,Docker 版本为1.0.1。其他版本的可能存在一些差异,读者请酌情参考。记录的同时也把出现的错误一同记录下来了。注意以下操作都使用了sudo进行了权限提升,记录中没有体现出来。
安装
$ apt-get install docker.io
E: Failed to fetch http://cn.archive.ubuntu.com/u ... 4.deb Size mismatch
E: Failed to fetch http://cn.archive.ubuntu.com/u ... l.deb Size mismatch
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
出错了,错误提示里面提示了怎么处理,按照提示做。
apt-get update
apt-get install docker.io --fix-missing
OK,安装成功了 。
基本操作
查看基本信息
service docker.io status
docker.io start/running, process 9220
docker -v
Docker version 1.0.1, build 990021a
docker images
没东西
获取image
想找符合自己要求的镜像可以在hub.docker.com找,比如找一个安装好http server的,找一个具备开发环境的。一般会找到符合自己需求的,这样就不需要自己搭建环境了。下面笔者下载安装了ubuntu 14.04.3的image。
docker search ubuntu
docker pull ubuntu:14.04.3
使用下面的命令可以看到系统里们已经存在的镜像
docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
ubuntu 14.04 91e54dfb1179 5 weeks ago 188.4 MB
运行容器
docker run -i -t ubuntu:14.04.3 /bin/bash
退出容器
exit
提交镜像
注意:退出容器后,之前所有操作都不会保存,要保存需要在退出之前,使用commit命令再生成一个image。下面命令先查看了当前运行着的容器,然后将当前容器的状态保存为一个新镜像。保存后就可以退出了,下次启动容器使用新的镜像,上次的操作就会保留着,这样每次你做了修改,如果需要保存,就要提交一个新的镜像。
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cc6c51bbfff6 ubuntu:14.04 /bin/bash 3 minutes ago Up 3 minutes nostalgic_nobel
docker commit cc6c51bbfff6 ubuntu:14.04+
573049725ed15eaffe3fd42be6ec995200da9ea3e201fe7cd3e21628fd588fef
容器内安装ssh服务
启动进入容器后,安装openssh-server,然后修改/etc/ssh/sshd_config文件,修改内容见下面。然后提交当前镜像,保存操作。
apt-get install openssh-server
PermitRootLogin yes
UsePAM no
docker commit cc6c51bbfff6 ubuntu:14.04+openssh-server
接下来退出原来的容器,使用新的镜像启动容器,并做好端口映射。
docker run -i -t -p 50001:22 ubuntu:14.04+openssh-server /bin/bash
/usr/sbin/sshd
此时你另开一个终端,就可以使用ssh客户端登录容器进行操作了
ssh 127.0.0.1 -p 50001
镜像的导出与导入
docker save ubuntu:14.04+openssh-server >/home/andrew/ubuntu.tar
docker load <ubuntu.tar
挂载宿主目录
docker run -i -t -v /home/andrew:/opt 91e54dfb1179 /bin/bash
通过-v参数,冒号前为宿主机目录,必须为绝对路径,冒号后为镜像内挂载的路径。默认挂载的路径权限为读写。如果指定为只读可以用:ro
docker run -i -t -v /home/andrew:/opt:ro 91e54dfb1179 /bin/bash
AP、路由、中继、桥接、客户端模式之间的区别
博客 • blog 发表了文章 • 0 个评论 • 92 次浏览 • 2017-10-11 22:07
注意:有的型号的TP-Link 迷你无线路由器上只有AP(接入点)、Router(无线路由)、Repeater(中继)这3种模式。
一、AP(接入点)模式
AP(接入点)模式下,只需要把一根可以上网的网线插在路由器上,无需任何配置就可以上网了;但需要注意这时候路由器上的无线网络未加密,建议设置一个无线密码。
在此模式下,该设备相当于一台无线HUB,可实现无线之间、无线到有线、无线到广域网络的访问。最常见的能够提供无线客户端的接入,例如:无线网卡接入等。
具体设置步骤:该产品出厂默认是AP模式,用网线将设备与宽带接口连接,搜索该设备的无线信号进行连接,把无线IP地址改为自动获取即可(一般情况下,宽带路由器提供分配IP地址功能,DHCP)。
多数单纯性无线AP本身不具备路由功能,包括DNS、DHCP、Firewall在内的服务器功能都必须有独立的路由或是计算机来完成。目前大多数的无线AP都支持多用户(30-100台电脑)接入,数据加密,多速率发送等功能,在家庭、办公室内,一个无线AP便可实现所有电脑的无线接入。
AP即可以和无线网卡建立无线连接,也可以和有线网卡通过网线建立有线连接。
在这种模式下,无线1到13。选择中应该注意的是,如果周围环境中还有其他的无线网络,尽量不要与它使用相同的频率段。
适用场所:例如宾馆、酒店或者其它提供了一根网线上网的场所,通过无线AP可以满足笔记本、手机等设备无线访问互联网。
二、Router(无线路由)模式
在Router(无线路由)模式下,路由器就相当于一台普通的无线宽带路由器;需要连接ADSL Modem(猫)或者光猫等设备来进行配置。
光猫相当于一个桥,桥接光纤口和接路由器WAN的网口,并进行协议转换,路由器负责拨号,并进行路由和NAT。(这种情况也可以让光猫拨号,接路由器LAN口,路由器工作在AP模式进行上网。)
适用场所:用户自己办理了宽带业务情况下使用。
三、Repeater(中继)模式
Repeater(中继)模式下,路由器会通过无线的方式与一台可以上网的无线路由器建立连接,用来放大可以上网的无线路由器上的无线信号;无线中继器是解决信号受损、衰减等问题的一个有效解决方案。
注意:放大后的无线信号的名称和原来的无线路由器的无线信号名称一致。
适用场所:有一台可以上网的无线路由器,但是该无线路由器的无线信号覆盖有线,希望无线信号可以覆盖更广泛的范围时使用。
四、Bridge(桥接)模式
Bridge(桥接)模式,路由器会通过无线的方式与一台可以上网的无线路由器建立连接,用来放大可以上网的无线路由器上的无线信号;
注意:放大后的无线信号的名称和原来的无线路由器的无线信号名称不一样。
适用场所:有一台可以上网的无线路由器,但是该无线路由器的无线信号覆盖有线,希望无线信号可以覆盖更广泛的范围时使用。
Repeater(中继)模式和Bridge(桥接)模式都是通过无线的方式连接到一台可以上网的无线路由器上,无线桥接目的在于连接两个不同的局 域网,中继用于扩大同一个无线网络的覆盖范围。无线桥接会出现两个单独的SSID,即使设置成一样的SSID,还是会显示出多个,中继不管连多少 AP,SSID只有一个。简单的说:无线中继的作用是扩大一个局域网的覆盖范围,而无线桥接的作用是把多个局域网连起来,从而也达到了拓展无线网络覆盖范 围的目的。本质不同,目的相同。
五、Client(客户端)模式
Client(客户端)模式下,路由器相当于一块无线网卡,用来接收其它无线路由器上的无线信号;电脑只能够通过网线连接到路由器上使用。
适用场所:附近有无线信号,并且用户知道该无线信号密码,用户的台式电脑想连接该无线信号上网时使用。 查看全部
注意:有的型号的TP-Link 迷你无线路由器上只有AP(接入点)、Router(无线路由)、Repeater(中继)这3种模式。
一、AP(接入点)模式
AP(接入点)模式下,只需要把一根可以上网的网线插在路由器上,无需任何配置就可以上网了;但需要注意这时候路由器上的无线网络未加密,建议设置一个无线密码。
在此模式下,该设备相当于一台无线HUB,可实现无线之间、无线到有线、无线到广域网络的访问。最常见的能够提供无线客户端的接入,例如:无线网卡接入等。
具体设置步骤:该产品出厂默认是AP模式,用网线将设备与宽带接口连接,搜索该设备的无线信号进行连接,把无线IP地址改为自动获取即可(一般情况下,宽带路由器提供分配IP地址功能,DHCP)。
多数单纯性无线AP本身不具备路由功能,包括DNS、DHCP、Firewall在内的服务器功能都必须有独立的路由或是计算机来完成。目前大多数的无线AP都支持多用户(30-100台电脑)接入,数据加密,多速率发送等功能,在家庭、办公室内,一个无线AP便可实现所有电脑的无线接入。
AP即可以和无线网卡建立无线连接,也可以和有线网卡通过网线建立有线连接。
在这种模式下,无线1到13。选择中应该注意的是,如果周围环境中还有其他的无线网络,尽量不要与它使用相同的频率段。
适用场所:例如宾馆、酒店或者其它提供了一根网线上网的场所,通过无线AP可以满足笔记本、手机等设备无线访问互联网。
二、Router(无线路由)模式
在Router(无线路由)模式下,路由器就相当于一台普通的无线宽带路由器;需要连接ADSL Modem(猫)或者光猫等设备来进行配置。
光猫相当于一个桥,桥接光纤口和接路由器WAN的网口,并进行协议转换,路由器负责拨号,并进行路由和NAT。(这种情况也可以让光猫拨号,接路由器LAN口,路由器工作在AP模式进行上网。)
适用场所:用户自己办理了宽带业务情况下使用。
三、Repeater(中继)模式
Repeater(中继)模式下,路由器会通过无线的方式与一台可以上网的无线路由器建立连接,用来放大可以上网的无线路由器上的无线信号;无线中继器是解决信号受损、衰减等问题的一个有效解决方案。
注意:放大后的无线信号的名称和原来的无线路由器的无线信号名称一致。
适用场所:有一台可以上网的无线路由器,但是该无线路由器的无线信号覆盖有线,希望无线信号可以覆盖更广泛的范围时使用。
四、Bridge(桥接)模式
Bridge(桥接)模式,路由器会通过无线的方式与一台可以上网的无线路由器建立连接,用来放大可以上网的无线路由器上的无线信号;
注意:放大后的无线信号的名称和原来的无线路由器的无线信号名称不一样。
适用场所:有一台可以上网的无线路由器,但是该无线路由器的无线信号覆盖有线,希望无线信号可以覆盖更广泛的范围时使用。
Repeater(中继)模式和Bridge(桥接)模式都是通过无线的方式连接到一台可以上网的无线路由器上,无线桥接目的在于连接两个不同的局 域网,中继用于扩大同一个无线网络的覆盖范围。无线桥接会出现两个单独的SSID,即使设置成一样的SSID,还是会显示出多个,中继不管连多少 AP,SSID只有一个。简单的说:无线中继的作用是扩大一个局域网的覆盖范围,而无线桥接的作用是把多个局域网连起来,从而也达到了拓展无线网络覆盖范 围的目的。本质不同,目的相同。
五、Client(客户端)模式
Client(客户端)模式下,路由器相当于一块无线网卡,用来接收其它无线路由器上的无线信号;电脑只能够通过网线连接到路由器上使用。
适用场所:附近有无线信号,并且用户知道该无线信号密码,用户的台式电脑想连接该无线信号上网时使用。
MinGW & VC -- DLL
博客 • blog 发表了文章 • 0 个评论 • 47 次浏览 • 2017-10-11 22:01
Mingw 生成dll
gcc test.c -shared -o libtest.dll -Wl,--output-def,libtest.def,--out-implib,libtest.a
同时生成了 a.def liba.a
VC (VC6.0)生成dll
File->New->Win32 Dynamic-Link Library …
添加代码使用__declspec(dllexport) 或者使用def文件配置好导出函数或变量
编译…
会生成 dll 和 lib两个文件
Mingw使用Mingw生成的dll
静态调用
gcc test_main.c –o test_main.exe –L. –llibtest
动态调用
编译
gcc test_main.c –o test_main.exe –lkernel32
代码
#include
…
HMODULE hdll = LoadLibrary("libtest.dll");
If(hdll != NULL) {
函数指针= GetProcAddress(hdll, "函数名");
函数指针();
}
动态调用使用GetProcAddress取得函数指针时必须使用生成的def文件中指明的函数名
使用g++编译出的dll 由于C++函数重载的原因会改变函数名
VC使用VC生成的dll
静态调用
Project->Setting->Link->Project Options 填入libtest.lib
编译…
libtest.dll 拷贝至运行目录
运行程序
动态调用
不需要libtest.lib 代码与mingw动态调用同
注意函数名也需要使用 def文件中指明的函数名
Mingw使用VC生成的dll
有两种比较常用函数调用约定 __cdecl __stdcall
1、如果dll中函数调用约定为__cdecl
使用时mingw可直接通过-l链接该dll
gcc sample.c –o sample.exe –L.-llib_a.dll
代码中包含dll的头文件然后就可以调用dll中的函数了
2、如果dll中的函数调用约定为__stdcall
则mingw就不能直接链接了
Windows底层api全部为__stdcall调用约定
因此api不能直接调用 但mingw已经帮我们生成了一批可以直接调用的库文件
在mingw安装目录的lib文件夹下
如果我们想链接kernel32.dll则可以直接使用-lkernel32
gcc会链接lib下的libkernel32.a 通过.a调用真正的kernel32.dll
如果我们有一个__stdcall调用约定的dll文件 则需要通过以下步骤自己生成.a文件
pexports xxx.dll > xxx.def
dlltool --dllname xxx.dll --def xxx.def --output-lib libxxx.dll.a
(pexports 需要到网上自行下载 dlltool为mingw自带的工具)
生成.a文件后就可以使用-l链接 在运行程序时需要将dll 放在运行目录下
一般情况下使用VC生成的dll文件都是__cdecl调用约定 因此一般情况下 VC生成的dll mingw可以直接通过-l选项链接
除非定义函数时显示指定__stdcall调用约定
VC使用Mingw生成的dll
VC无法使用Mingw的a文件也不能像mingw那样直接调用MinGW生成dll文件
如果调用mingw生成的dll则需要通过以下步骤得到相应的lib文件通过lib文件调用
pexports xxx.dll > xxx.def
lib /machine:ix86 /def:xxx.def
(lib为VC自带的工具)
生成了lib文件后剩下的就和VC调用VC产生的dll 类似了
(目前测试 Mingw产生dll时 .h文件中的函数需使用 extern "c" 声明导出函数可以使用导出变量还不可以不知道哪里还需要下点功夫) 查看全部
Mingw 生成dll
gcc test.c -shared -o libtest.dll -Wl,--output-def,libtest.def,--out-implib,libtest.a
同时生成了 a.def liba.a
VC (VC6.0)生成dll
File->New->Win32 Dynamic-Link Library …
添加代码使用__declspec(dllexport) 或者使用def文件配置好导出函数或变量
编译…
会生成 dll 和 lib两个文件
Mingw使用Mingw生成的dll
静态调用
gcc test_main.c –o test_main.exe –L. –llibtest
动态调用
编译
gcc test_main.c –o test_main.exe –lkernel32
代码
#include
…
HMODULE hdll = LoadLibrary("libtest.dll");
If(hdll != NULL) {
函数指针= GetProcAddress(hdll, "函数名");
函数指针();
}
动态调用使用GetProcAddress取得函数指针时必须使用生成的def文件中指明的函数名
使用g++编译出的dll 由于C++函数重载的原因会改变函数名
VC使用VC生成的dll
静态调用
Project->Setting->Link->Project Options 填入libtest.lib
编译…
libtest.dll 拷贝至运行目录
运行程序
动态调用
不需要libtest.lib 代码与mingw动态调用同
注意函数名也需要使用 def文件中指明的函数名
Mingw使用VC生成的dll
有两种比较常用函数调用约定 __cdecl __stdcall
1、如果dll中函数调用约定为__cdecl
使用时mingw可直接通过-l链接该dll
gcc sample.c –o sample.exe –L.-llib_a.dll
代码中包含dll的头文件然后就可以调用dll中的函数了
2、如果dll中的函数调用约定为__stdcall
则mingw就不能直接链接了
Windows底层api全部为__stdcall调用约定
因此api不能直接调用 但mingw已经帮我们生成了一批可以直接调用的库文件
在mingw安装目录的lib文件夹下
如果我们想链接kernel32.dll则可以直接使用-lkernel32
gcc会链接lib下的libkernel32.a 通过.a调用真正的kernel32.dll
如果我们有一个__stdcall调用约定的dll文件 则需要通过以下步骤自己生成.a文件
pexports xxx.dll > xxx.def
dlltool --dllname xxx.dll --def xxx.def --output-lib libxxx.dll.a
(pexports 需要到网上自行下载 dlltool为mingw自带的工具)
生成.a文件后就可以使用-l链接 在运行程序时需要将dll 放在运行目录下
一般情况下使用VC生成的dll文件都是__cdecl调用约定 因此一般情况下 VC生成的dll mingw可以直接通过-l选项链接
除非定义函数时显示指定__stdcall调用约定
VC使用Mingw生成的dll
VC无法使用Mingw的a文件也不能像mingw那样直接调用MinGW生成dll文件
如果调用mingw生成的dll则需要通过以下步骤得到相应的lib文件通过lib文件调用
pexports xxx.dll > xxx.def
lib /machine:ix86 /def:xxx.def
(lib为VC自带的工具)
生成了lib文件后剩下的就和VC调用VC产生的dll 类似了
(目前测试 Mingw产生dll时 .h文件中的函数需使用 extern "c" 声明导出函数可以使用导出变量还不可以不知道哪里还需要下点功夫)
static and dynamic lib
博客 • blog 发表了文章 • 0 个评论 • 44 次浏览 • 2017-10-11 22:00
Windows下的dll和lib
简介
DLL就是动态链接库 LIB是静态链接库
DLL是程序在运行阶段才需要的文件
LIB是程序编译时需要链接的文件
使用静态库
静态库实际上是obj文件打包而成
使用静态库时 在程序中加入
#pragma comment(lib, "WSock32.lib")
或者通过编译器项目设置中 手动添加Lib静态库
这样在链接程序 就会将静态库链接到程序里面 生成一个可执行文件或其他目标文件
使用动态库
动态库是一个标准的PE文件 经过编译器编译链接的
动态库一般会有两个文件 ws32.dll ws32.lib
这里的lib并不是上面介绍的静态库 他只包含了一些跳转指令
真正的执行命令在dll中
动态库的使用有两种方式
一是有系统负责加载dll
这种方式调用dll时 需要在程序编译时将lib链接到程序中
就像添加静态库一样
程序运行时 系统加载dll 执行dll中命令
二是显示加载dll
这种方式调用不需要lib文件
程序运行时 使用loadlibrary等api 显示加载dll
取得里面的函数指针 调用
动态库函数的导出
这里只介绍两种方式
一是使用模块定义文件(.def文件) 二是使用__declspec(dllexport)关键字
使用.def文件导出
优点:
1、能控制导出函数名字 在导出C++函数时 可以控制函数名不出现乱码 如func@123axx
2、你能控制导出函数的序号
特别适用于第三方DLL的制作
def文件格式:
LIBRARY dll名称
EXPORTS
func1 @1
func2 @2
把def文件和代码放在同一级目录下 编译dll时 会自动载入def生成dll
使用__declspec(dllexport)
优点是简单 方便 但无法完成上面.def的工作 一般用于应用程序自己使用的DLL
当DLL更新后 要使用新的DLL 也需要应用重新编译链接
Dll中设置共享可读写变量
Dll中全局变量是可以供多个进程共享的 但如果有一个进程修改了
Dll会使用页面拷贝机制 为该进程维护一个单独的页面 将原有原有数据拷贝过来
然后修改为该进程的值
这样其他进程依然使用原来的页面 所有这个进程对变量的修改 不会影响其他进程
如果我想设置一个变量 让一个进程修改他的值 其他进程也能看到
则必须建立一个共享的节 将共享变量放到节中 告诉dll 这里的东西是共享的
如果我改变他 不要使用页面拷贝机制
创建节的方法(放在原代码文件中):
#pragma data_seg("MySec") //MySec是新创建的节的名字(不能超过8个字节)
HWND g_hWnd=NULL; //新变量必须初始化,否则没有新建节的信息
#pragma data_seg() //以上为新建节
新创建的节 共享后才有效 共享的两种方法
1、#pragma comment(linker,"/section:MySec,RWS") //设置节的属性,读,写,共享
2、也可以把#pragma comment(linker,"/section:MySec,RWS")省略。
在.def文件中添加如下代码:
SEGMENTS
MySec read write shared
也能对节的属性进行设置
Linux 下的.so .a
.a静态库 使用ar命令将一个或多个.o文件打包成.a文件
编译时使用 –llib链接
.a静态库的生成
ar cru libxxx.a x.o xx.o xxx.o
ranlib libxxx.a #更新静态库函数表
动态库使用gcc编译生成
gcc –shared –fPIC xx.c –o libxx.so 查看全部
Windows下的dll和lib
简介
DLL就是动态链接库 LIB是静态链接库
DLL是程序在运行阶段才需要的文件
LIB是程序编译时需要链接的文件
使用静态库
静态库实际上是obj文件打包而成
使用静态库时 在程序中加入
#pragma comment(lib, "WSock32.lib")
或者通过编译器项目设置中 手动添加Lib静态库
这样在链接程序 就会将静态库链接到程序里面 生成一个可执行文件或其他目标文件
使用动态库
动态库是一个标准的PE文件 经过编译器编译链接的
动态库一般会有两个文件 ws32.dll ws32.lib
这里的lib并不是上面介绍的静态库 他只包含了一些跳转指令
真正的执行命令在dll中
动态库的使用有两种方式
一是有系统负责加载dll
这种方式调用dll时 需要在程序编译时将lib链接到程序中
就像添加静态库一样
程序运行时 系统加载dll 执行dll中命令
二是显示加载dll
这种方式调用不需要lib文件
程序运行时 使用loadlibrary等api 显示加载dll
取得里面的函数指针 调用
动态库函数的导出
这里只介绍两种方式
一是使用模块定义文件(.def文件) 二是使用__declspec(dllexport)关键字
使用.def文件导出
优点:
1、能控制导出函数名字 在导出C++函数时 可以控制函数名不出现乱码 如func@123axx
2、你能控制导出函数的序号
特别适用于第三方DLL的制作
def文件格式:
LIBRARY dll名称
EXPORTS
func1 @1
func2 @2
把def文件和代码放在同一级目录下 编译dll时 会自动载入def生成dll
使用__declspec(dllexport)
优点是简单 方便 但无法完成上面.def的工作 一般用于应用程序自己使用的DLL
当DLL更新后 要使用新的DLL 也需要应用重新编译链接
Dll中设置共享可读写变量
Dll中全局变量是可以供多个进程共享的 但如果有一个进程修改了
Dll会使用页面拷贝机制 为该进程维护一个单独的页面 将原有原有数据拷贝过来
然后修改为该进程的值
这样其他进程依然使用原来的页面 所有这个进程对变量的修改 不会影响其他进程
如果我想设置一个变量 让一个进程修改他的值 其他进程也能看到
则必须建立一个共享的节 将共享变量放到节中 告诉dll 这里的东西是共享的
如果我改变他 不要使用页面拷贝机制
创建节的方法(放在原代码文件中):
#pragma data_seg("MySec") //MySec是新创建的节的名字(不能超过8个字节)
HWND g_hWnd=NULL; //新变量必须初始化,否则没有新建节的信息
#pragma data_seg() //以上为新建节
新创建的节 共享后才有效 共享的两种方法
1、#pragma comment(linker,"/section:MySec,RWS") //设置节的属性,读,写,共享
2、也可以把#pragma comment(linker,"/section:MySec,RWS")省略。
在.def文件中添加如下代码:
SEGMENTS
MySec read write shared
也能对节的属性进行设置
Linux 下的.so .a
.a静态库 使用ar命令将一个或多个.o文件打包成.a文件
编译时使用 –llib链接
.a静态库的生成
ar cru libxxx.a x.o xx.o xxx.o
ranlib libxxx.a #更新静态库函数表
动态库使用gcc编译生成
gcc –shared –fPIC xx.c –o libxx.so