背景:有时程序偶出现参数少了或没有提交到下一个链接Url里后出现问题,如何查呢,最好的办法是在nginx上的加post参数,以定位到问题才有可能对某个UIR的代码出现的问题进行排查。
og_format access '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent $request_body "$http_referer" "$http_user_agent" $http_x_forwarded_for';
access_log logs/test.access.log access;

注意放的位置在http里:nginx: [warn] the "log_format" directive may be used only on "http" level in /usr/local/nginx/conf/vhost/xxx.conf:59
nginx.conf
http里定义:wwwlog
   log_format  wwwlog  '$remote_addr - $remote_user [$time_local] "$request" '                                                                                                                      
              '$status $body_bytes_sent "$http_referer" '
              '"$http_user_agent" $http_x_forwarded_for "$request_time"';

在include每个域名里后面加上wwwlog:
access_log  /data/logs/access_mytv.log wwwlog;

于是在同样的access后这样写:

日志如下:
202.108.16.77 - - [14/Jan/2015:10:45:45 +0800] "POST /partin/releaseinfo HTTP/1.1" 302 5 id=47&choice_type=new&eid=338&videoid=5d6dabda-9b97-11e4-9584-21fa84a4ab6e&file_ext=mp4&lang=zh&upload_server=202.108.17.15&title=7%E5%B2%81%E5%B0%8F%E5%AD%A9%E9%85%92%E7%93%B6%E4%B8%8A%E5%81%9A%E4%BF%AF%E5%8D%A7%E6%92%91%E8%B9%BF%E7%BA%A2%E7%BD%91%E7%BB%9C&desc=7%E5%B2%81%E5%B0%8F%E5%AD%A9%E9%85%92%E7%93%B6%E4%B8%8A%E5%81%9A%E4%BF%AF%E5%8D%A7%E6%92%91%E8%B9%BF%E7%BA%A2%E7%BD%91%E7%BB%9C&tags=%E6%B5%8B%E8%AF%95%E4%B8%80%E4%B8%8B%E3%80%82&checkflag=on "http://jackxiang.com/partin/showupload/activityid/47" "Mozilla/5.0 (Windows NT 6.1; rv:34.0) Gecko/20100101 Firefox/34.0" -

POST URI及参数:POST /partin/releaseinfo HTTP/1.1" 302 5  .....
来自的refer Uri:http://jackxiang.com/partin/showupload/activityid/47


这个access_log的log_format应该可以定义多个不同的名供不同日志的需求。

再就是,
get请求的参数就是存放在http header中的,所以修改header的大小限制 当然可以解决请求串过长的问题啦。
阅读全文
前置:Linux多进程和多线程的一次gdb调试实例:https://typecodes.com/cseries/multilprocessthreadgdb.html ,Linux C/C++开发中gdb进行多进程和多线程的调试一直比较麻烦,在CSDN上看到高科的一篇文章《gdb调试多进程和多线程命令》比较有启发,这里就自己重新整理并做了一个GDB多进程/线程的调试实践。
这个表很重要,两个参数一块用:


也可将前面的set添加到~/.gdbinit来打开non-stop模式:


查看相关命令:
set follow-fork-mode child
set detach-on-fork off
info inferiors                    #####显示正在调试的进程
inferior 2
show detach-on-fork #Whether gdb will detach the child of a fork is off.
show follow-fork-mode #Debugger response to a program call of fork or vfork is "child"
info b #查看断点
进程树:
pstree -pul
PS查看自己程序名运行的多进程:
ps -f -C multepoolser

break  if
要想设置一个条件断点,可以利用break if命令,如下所示:
[cpp] view plain copy
(gdb) break line-or-function if expr  
(gdb) break 46 if testsize==100  
clean number
清除原文件中某一代码行上的所有断点
注:number 为原文件的某个代码行的行号


断点的管理
1. 显示当前gdb的断点信息: info break
2. delete 删除指定的某个断点: delete breakpoint

单步执行
continue      继续运行程序直到下一个断点(类似于VS里的F5)
next            逐过程步进,不会进入子函数(类似VS里的F10)  #这个不进入函数里。
setp            逐语句步进,会进入子函数(类似VS里的F11) 的确能进入到函数里面。
until           运行至当前语句块结束  #没弄明白,试了试没找到规律
finish          运行至函数结束并跳出,并打印函数的返回值(类似VS的Shift+F11)
next/n 不进入的单步执行 step 进入的单步执行
finish
如果已经进入了某函数,而想退出该函数返回到它的调用函数中,可使用命令finish
call name
调用和执行一个函数
(gdb) call gen_and_sork( 1234,1,0 )  
(gdb) call printf(“abcd”)  
$1=4  
finish 结束执行当前函数,显示其返回值(如果有的话)

原文件的搜索 search text
该命令可显示在当前文件中包含text串的下一行。
reverse-search text
该命令可以显示包含text 的前一行。

set variable 给变量赋值
signal 将一个信号发送到正在运行的进程
watch 在程序中设置一个监测点(即数据断点)
whatis 显示变量或函数类型

来自GDB调试精粹:http://blog.csdn.net/lwbeyond/article/details/7839225

GDB打印所有字符串:@ http://blog.csdn.net/shuizhizhiyin/article/details/53227913

如果出现No symbol "header_line" in current context.,你得切换到那个进程里面去,能切换进去的前提是你提前打了断点:
(gdb) p header_line
No symbol "header_line" in current context.
可:info thread 切换到对应的进程,再打印也就有了。


break FileName.cpp:LinuNum thread all:所有线程都在文件FileName.cpp的第LineNum行有断点。
thread apply ID1 ID2 IDN command:多个线程执行gdb命令command。
thread apply all command:所有线程都执行command命令。
set scheduler-locking off|on|step:在调式某一个线程时,其他线程是否执行。off,不锁定任何线程,默认值。on,锁定其他线程,只有当前线程执行。step,在step(单步)时,只有被调试线程运行。
set non-stop on/off:当调式一个线程时,其他线程是否运行。
set pagination on/off:在使用backtrace时,在分页时是否停止。
set target-async on/ff:同步和异步。同步,gdb在输出提示符之前等待程序报告一些线程已经终止的信息。而异步的则是直接返回。
来自:http://blog.csdn.net/helloktt/article/details/73252943
http://www.tolxs.com/?p=302
(gdb)  show detach-on-fork
Whether gdb will detach the child of a fork is off.
(gdb) show follow-fork-mode
Debugger response to a program call of fork or vfork is "child"

出现:
(gdb) n
Cannot execute this command while the selected thread is running.

(gdb) info threads
  Id   Target Id         Frame
  3    Thread 0x7fffece72700 (LWP 27660) "multepoolser" handleEpollRdMessage (threadNum=0) at multepoolser.c:262
* 2    Thread 0x7ffff7fde840 (LWP 21243) "multepoolser" (running)
  1    Thread 0x7ffff7fde840 (LWP 21239) "multepoolser" 0x00007ffff668774c in fork () from /lib64/libc.so.6

root     21239 16286  0 17:22 pts/1    00:00:00 [httpmut: master process] master process
apache   21243 21239  0 17:22 pts/1    00:00:00 [httpmut: worker process] worker process

目前在进程:2,前面有*号,我得到3上面去,怎么弄?
thread 3
(gdb) thread 3
[Switching to thread 3 (Thread 0x7fffece72700 (LWP 27660))]
#0  handleEpollRdMessage (threadNum=0) at multepoolser.c:262
262         printf("handleEpollRdMessage function 's threadNum=%d\n",threadNum);
(gdb) n
handleEpollRdMessage function 's threadNum=0
263         int recvlen=-1,epollRdQueRet=-1;//返回
info threads #此时就在3了吧
(gdb) info threads
  Id   Target Id         Frame
* 3    Thread 0x7fffece72700 (LWP 27660) "multepoolser" handleEpollRdMessage (threadNum=0) at multepoolser.c:263
  2    Thread 0x7ffff7fde840 (LWP 21243) "multepoolser" (running)
  1    Thread 0x7ffff7fde840 (LWP 21239) "multepoolser" 0x00007ffff668774c in fork () from /lib64/libc.so.6

卡这儿了,也就是主进程网络那边没有来Epoll句柄,getepollRdFromQue队列一直是空的,怎么办?
(gdb) p epollRdQueRet
$2 = -1
(gdb) n
455         }
(gdb)
302             epollRdQueRet = getepollRdFromQue(&sockRdQue[threadNum],&epollRd);//只要有生产的fd进来并该线程获取到了,就立即去epoll读队列里抢,一线程一队列,不用锁。
(gdb)
303             if(epollRdQueRet == -1) continue;//没有获取到epollRd,继续获取。
(gdb)
455         }

此时如果有的进程需要运行,怎么办?GDB命令:thread apply 3 1 continue #让线程3继续运行,注意我顾意把主线程1也continue。
thread apply 3 1 2 continue


需要实践,链接如下:
http://blog.sina.com.cn/s/blog_53fab15a0101g88r.html
https://www.cnblogs.com/frankbadpot/archive/2010/06/23/1762916.html
http://blog.csdn.net/wangyin159/article/details/47169267

=============================================================================

背景:当你在做一些多进程调试时,会出现一个问题,那就是子进程往往不太好调试,怎么办?如果子进程一直在while里飞快的运行着怎么办,这篇文章就是教会你进行双gdb调试,以实现了子进程的调试,这儿在没有调试时,其子进程是不断的打印,当然最好在while里加一个sleep,但第二个gdb进入后则会存在第一个gdb的打印变慢了,此时,可以在第二个gdb里打印相关变量,达到对子进程的调试目的,特别注意的是,第二个gdb一定要在那个子进程的行里break(这儿是31行)进行调试,而不是放在其它地方,否则是没法调试到子进程的。第三个是:进程中断点.然后用c(这里要用continue,因为attach的进程已经在运行了,不能用run)。最后,子进程死了父亲进程拉起,crack这块可能是return退出了,自己打印是crack,导致并不是真正的crack了,也就不是coredump了,特别注意这个问题。
     当你在程序中使用fork(),如果用gdb来调试.不管是你在子进程是否设置断点.你都只能在父进程单步调试,而没办法进入到子进程当中进行单步调试.因为gdb的所有处理(查看堆栈,内存,变量值)都是针对当前进程空间.

那么是否就没办法调试多进程程序的子进程代码呢?办法还是有的,一般的标准方法是再打开一个gdb用attach功能来调试子进程gdb attach 功能是不执行被调试程序,而是把gdb“挂”到一个已经运行的进程之上来进行调试,这挂载的动作称为attach.当然也包括挂载子进程。

注意两点:
0.当主gdb进来后进行断点后,子进程尽管断点了,但依然运行(为第二个gdb作暂停准备之用),而当第二个gdb对子进程进行attach后,其主gdb的子进程的打印动作也就暂停(为方便调试,可以在进程启动后,设定sleep一段时间,如30s,其实只要第二个gdb一attach到子进程,子进程就柱塞了。),此时子gdb再进行设置断点,按c运行,按n作next就行。
1.子进程的主gdb点和第二个gdb的break点要同一行?不必要,其主gdb只是起到在第二个gdb单独调该进程时起到暂停其主的子进程的作用罢了。
2.在子进程的gdb里,要用c来继续,(这里要用continue,因为attach的进程已经在运行了,不能用run!(也就是:主进程用r(先运行着,主进程不退出。),子进程用c,继续在原来那个停下来的点继续运行到后,再用n命令,即next一步一步查问题,n(next):显示的是即将运行这一行,也就是还没有运行。)
3.gdb调试epoll时遇到的Interrupted system call:
signal(SIGALRM,timer_handle);
最近写了个多线程数据处理的程序,其中用到sem_wait()在信号量为0的时候挂起程序. 程序全速执行的时候没有任何问题,但gdb单步调试的时候,因执行sem_wait()函数而挂起的线程经常出现Interrupted system call,不能正常执行.
    原因在于,gdb单步调试的时候会在断点处插入一条中断指令,当程序执行到该断点处的时候会发送一个SIGTRAP信号,程序转去执行中断相应,进而gdb让程序停下来进行调试. 对于sem_wait\wait\read等会阻塞的函数在调试时,如果阻塞,都可能会收到调试器发送的信号,而返回非0值.
    为了解决这个问题需要在代码中忽略由于接收调试信号而产生的"错误"返回:


到一篇文章《gdb常用命令及使用gdb调试多进程多线程程序》:http://www.cnblogs.com/33debug/p/7043437.html ,代码编译无法通过,代码调整如下,gdb_pthread.c:



关于GDB无法调试epoll的疑问?
这种交互式的网络程序最好不用gdb来调?
调试网络通讯程序最好别用GDB,epoll你可以用strace,gdb是用来调试 C数据结构逻辑之类的。
打日志是我的首选调试方法,如果程序崩溃就看core 文件,如果死锁就 attach上去,其他的错误我从不用GDB
不是epoll和gdb的问题,而是在gdb下epoll_wait 信号处理和正常运行有差异造成的,应该是这个。
摘自:http://bbs.chinaunix.net/thread-1551201-1-1.html

多进程调试如下所述即可,如下,特别是新的linux内核版本能支持到多进程了,相当好用:
在2.5.60版Linux内核及以后,GDB对使用fork/vfork创建子进程的程序提供了follow-fork-mode选项来支持多进程调试。
follow-fork-mode的用法为:
set follow-fork-mode [parent|child]
parent: fork之后继续调试父进程,子进程不受影响。
child: fork之后调试子进程,父进程不受影响。
因此如果需要调试子进程,在启动gdb后:
(gdb) set follow-fork-mode child

这块可以研究一下,新的内核及新的gdb有新功能很方便使用:
set follow-fork-mode child
//set detach-on-fork on //gdb控制父子进程,不让调试了: Can't attach LWP 24731: Operation not permitted,得打开:ON。
b 146 //main里的子进程行
b 192  //子进程调用的函数原型行
r //执行到子进程断点处
n //子进程单步执行

实践心得:一般情况下多线程的时候,由于是同时运行的,最好设置 set scheduler-locking on 这样的话,只调试当前线程 。
off 不锁定任何线程,也就是所有线程都执行,这是默认值。 on 只有当前被调试程序会执行。
vi bp.list

gdb.sh

(一)这块在调试epoll时,在n单步执行卡后(c执行前先断点),得通过浏览器模拟socket请求才能过得去,否则会一直卡那儿,如下:


这块如果continue后,中间因为断点就一次是没法下次进入的,需要引入gdb判断(if {expression} else end条件判断语句, if 后面所带的表达式为一般的GDB表达式:http://blog.csdn.net/horkychen/article/details/9372039)及观察点,才能更加深入了解,下面是试图没有断点运行起来后实现ctrl+C退出,想继续n的尝试:
(二)再就是对c后一直卡那儿,可以按ctrl+C退出( SIGINT   :来自键盘的中断信号 ( ctrl + c ) .),SIGTERM:kill 命令发出 的信号.,继续n执行:
Program received signal SIGINT, Interrupt.
0x0000003c9a2d3fd3 in __epoll_wait_nocancel () from /lib64/libc.so.6
(gdb) n
Single stepping until exit from function __epoll_wait_nocancel,
which has no line number information.

这块不知怎么回事....需要进一步学习了解。

Process(listenFd); //运行至工作子进程的函数,;b 192进行单步执行。

直接gdb后attach子进程:
#ps -f -C multepoolser
UID        PID  PPID  C STIME TTY          TIME CMD
root      2150 19720  0 17:09 pts/1    00:00:00 [httpmut: master process] master process
apache    2151  2150 93 17:09 pts/1    00:00:01 [httpmut: worker process] worker process
2151就是子进程,怎么办?
gdb   #运行gdb
attach 2151
现在就可以调试了。一个新的问题是,子进程一直在运行,attach上去后都不知道运行到哪里了。有没有办法解决呢?

一个办法是,在要调试的子进程初始代码中,比如main函数开始处,加入一段特殊代码,使子进程在某个条件成立时便循环睡眠等待,attach到进程后在该代码段后设上断点,再把成立的条件取消,使代码可以继续执行下去。

至于这段代码所采用的条件,看你的偏好了。比如我们可以检查一个指定的环境变量的值,或者检查一个特定的文件存不存在。以文件为例,其形式可以如下:

1
2
3
4
5
6
7
8
9
10
void debug_wait(char *tag_file)
{
    while(1)
    {
        if (tag_file存在)
            睡眠一段时间;
        else
            break;
    }
}
当attach到进程后,在该段代码之后设上断点,再把该文件删除就OK了。当然你也可以采用其他的条件或形式,只要这个条件可以设置/检测即可。

Attach进程方法还是很方便的,它能够应付各种各样复杂的进程系统,比如孙子/曾孙进程,比如守护进程(daemon process),唯一需要的就是加入一小段代码。

https://www.ibm.com/developerworks/cn/linux/l-cn-gdbmp/

学习参考:
http://blog.csdn.net/nyist327/article/details/40040011
http://blog.sina.cn/dpool/blog/s/blog_55d572ca0100v8e8.html

修改如下:


主gdb:
(gdb) b 167
Breakpoint 1 at 0x4025a1: file multipepollserver.cpp, line 167.
(gdb) b 147
Breakpoint 2 at 0x40250f: file multipepollserver.cpp, line 147.
(gdb) r
Starting program: /home/xiangdong/multepoolserver/multipepollserver
[Thread debugging using libthread_db enabled]
Detaching after fork from child process 27539.
[New Thread 0x2afb66031230 (LWP 27536)]

Breakpoint 1, main (argc=1, argv=0x7fff550003c8, envp=0x7fff550003d8) at multipepollserver.cpp:168
168    

辅助gdb:
(gdb) b 147
Breakpoint 1 at 0x40250f: file multipepollserver.cpp, line 147.
(gdb) c
Continuing.
n

以上代码来自,也就是上面的程序调试的整个代码放在:http://jackxiang.com/post/6937/  ,不完善进一步学习中。

来自:
    http://blog.sina.com.cn/s/blog_5cec1e1d0100guwf.html
    http://blog.csdn.net/qiaoliang328/article/details/7404032
    http://bbs.csdn.net/topics/380004392
首先我们看一个如下简单的多进程程序。
阅读全文
MarkMan – 马克鳗,让设计更有爱!
MarkMan – 马克鳗 是一款方便高效的标注工具,极大节省设计师在设计稿上添加和修改标注的时间,让设计更有爱。
一张标注了间距和长度的设计稿,才是有爱的设计稿。想做有爱的设计师,又想摆脱人肉标注的重体力劳动吗?
MarkMan – 马克鳗 可以很方便的为设计稿添加标记,双击、滚轮、拖动…

新版特性:
增加坐标、颜色、文字标记
优化界面设计和交互方式
加入全局放大镜(快捷键同PS)

背景:配置仓库结合svn版本控制工具
saltstack的安装使用
centos6.3_x86_64
安装EPEL第三方软件源
wget -c http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm
rpm -ivh epel-release-6-8.noarch.rpm
安装
yum install salt-master -y  //master
yum install salt-minion     //clients
chkconfig --list|grep salt   //master默认监听两个端口, 4505(publish_port)为salt的消息发布系统,4506(ret_port)为salt客户端与服务端通信的端口,所以确保客户端能跟服务端的这2个端口通信
salt-master     0:off   1:off   2:off   3:on    4:on    5:on    6:off
salt-syndic     0:off   1:off   2:off   3:on    4:on    5:on    6:off
chkconfig --list|grep salt   //clients   没有端口,只有进程
salt-minion     0:off   1:off   2:off   3:on    4:on    5:on    6:off
配置
/etc/init.d/salt-master start  //master直接启动,若也要作为clients,install salt-minino,修改master和id
vi /etc/salt/minion    //clients
master: 192.168.2.18   //冒号后面有空格
/etc/init.d/salt-minion start  
认证
salt-key -L //all list 详细可salt-key --help
实时管理
salt "localhost.localdomain" cmd.run "df -Th"
localhost.localdomain:
    Filesystem    Type    Size  Used Avail Use% Mounted on
    /dev/mapper/VolGroup-lv_root
                  ext4     19G  6.5G   11G  38% /
    tmpfs        tmpfs    244M     0  244M   0% /dev/shm
    /dev/sda1     ext4    485M   40M  420M   9% /boot
群发
salt "*" cmd.run "ls -al /opt/io.sh"
localhost.localdomain:
    -rwxr-xr-x 1 root root 396 Jun  8 18:22 /opt/io.sh
过滤匹配
salt '192.168.*' cmd.run 'echo hi'  
正常我们每台主机的HOSTS都是这样
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
为了区分开来并且MASTER也作为客户端
vi /etc/salt/minion
39 id: 192.168.2.18  //或者修改为自定义名称 比如 id: salt-master,修改id后客户端必须重启,salt-keys -L 才能认得到 然后加入-a 如果修改过ID,最好把旧的删掉 -d
salt-key -D      //删除所有KEY
salt-key -d key  //删除单个key
salt-key -A      //接受所有KEY
salt-key -a key  //接受单个key
[root@server1 salt]# salt-key -L
Accepted Keys:
Unaccepted Keys:
192.168.2.18
192.168.2.19
Rejected Keys:
[root@server1 salt]# salt-key -a 192.168.2.18
Key for minion 192.168.2.18 accepted.
[root@server1 salt]# salt-key -a 192.168.2.19
Key for minion 192.168.2.19 accepted.
[root@server1 salt]# salt-key -L
Accepted Keys:
192.168.2.18
192.168.2.19
Unaccepted Keys:
Rejected Keys:
测试服务端和客户端通讯
salt "192.168.2.19" test.ping     //单引号也可以
192.168.2.19:
    True
salt "*" salt.modules.disk    //salt.modules.disk  模块

服务端:
vi /etc/salt/master
nodegroups:
    mytest1: 'S@192.168.2.0/24'    
salt -N mytest1 test.ping
192.168.2.18:
    True
client1_2.19:
    True
KEYS名字  nodegroups:
    test1: 'L@192.168.2.18,client1_2.19' //多个
    test2: 'client1_2.19'   //单个

来自:http://www.2cto.com/os/201308/238485.html
核心中的核心:
gcc -shared -Wl,-soname,libhello.so.0 -o libhello.so.0.0.0 hello.o   #在生成可执行文件时就得有:libhello.so.0文件,即使是软链接也成,得有。动态链接版本库的标准用法,不标准用libhello.so 也成:gcc -shared -Wl,-soname,libhello.so -o libhello.so.0.0.0 hello.o

背景:共享库,主版本升级,即接口发生变化。
Linux 系统提供一个命令 ldconifg 专门为生成共享库的soname 文件,以便程序在加载时后通过soname 找到共享库。
1)real name:
咱生成的实体文件是:real name ==>libhello.so.0.0.0
readelf -d libhello.so.0.0.0 |grep SONAME
0x000000000000000e (SONAME)             Library soname: [libhello.so.0]
1.1.1234的是共享库的版本号,其主版本号+小版本号+build号。主板号,代表当前动态库的版本,如果动态库的接口有变化,那么这个版本号就要加1;后面的两个版本号(小版本号 和 build 号)是告诉你详细的信息,比如为一个hot-fix 而生成的一个版本,其小版本号加1,build号也应有变化。 这个文件名包含共享库的代码。

2)soname:
动态库的soname( Short for shared object name),其是应用程序加载dll 时候,其寻找共享库用的文件名。ldconfig会自动生成,格式为前面的realname:
   lib + math+.so + ( major version number)

3)link name:
共享库的连接名(link name),是专门为build 阶段连接而用的名字。这个名字就是lib + math +.so ,比如libmath.so。其是不带任何版本信息的。
例子,在编译时需要link name ,专门为build 阶段连接而用的名字,否者报错/usr/bin/ld: cannot find -lhello:(共享库的连接名(link name),是专门为build 阶段连接而用的名字。例子叫: libhello.so)
gcc  -o main main.o -lhello -L.
/usr/bin/ld: cannot find -lhello
解决办法:
ln -sf libhello.so.0 libhello.so

4)ldconfig自动找SONAME,生成SONAME名的共享库,如下:
最后,ldconfig时,是找那个SONAME,然后自动生成对应的共享库:
inux 系统提供一个命令 ldconifg 专门为生成共享库的soname 文件,以便程序在加载时后通过soname 找到共享库。
实践并证明如下(生成SONAME名:gcc -shared -Wl,-soname,libhello.so.0 -o libhello.so.0.0.0 hello.o ,名字叫:libhello.so.0 ,这块即使-L. 引用了,非软链接是libhello.so.0.0.0, 它会提示:/bin/ld: cannot find -lhello,这个:-soname指定名字后,-L会找它,无论是实体的libhello.so.0还是软链接都得有,否则会提示cannot find -lhello,当然,你可以直接写成:gcc -shared -Wl,-soname,libhello.so -o libhello.so.0.0.0 libhello.o ,gcc  -o main main.o -lhello -L.  ,它会找libhello.so文件是否存在,当然可以软链接:mv libhello.so libhello.so.0.0.0 ,ln -s libhello.so.0.0.0 libhello.so,再编译就能通过:gcc  -o main main.o -lhello -L.  ,至于运行还是得找:LD_LIBRARY_PATH和ldconfig进行帮忙。):
readelf -d /home/xiangdong/test/c/libhello.so.0.0.0|grep SONAME
0x000000000000000e (SONAME)             Library soname: [libhello.so.0]
cp /home/xiangdong/test/c/libhello.so.0.0.0 /usr/lib64/.
ldconfig -p|grep hello
ldconfig
ldconfig -p|grep hello
        libhello.so.0 (libc6,x86-64) => /usr/lib64/libhello.so.0  (这个自动由chkconfig生成的so就是前面生成的SONAME名,这一句:gcc -shared -Wl,-soname,libhello.so.0 -o libhello.so.0.0.0 hello.o)


升级问题:
1)共享库,小版本升级,即接口不变.
当升级小版本时,共享库的soname 是不变的,所以需要重新把soname 的那个连接文件指定新版本就可以。 调用ldconfig命令,系统会帮你做修改那个soname link文件,并把它指向新的版本呢。这时候你的应用程序就自动升级了。
2)共享库,主版本升级,即接口发生变化。
共享库,主版本升级,即接口发生变化。

  当升级主版本时,共享库的soname 就会加1.比如libhello.so.0.0.0 变为 libhello.so.1.0.0. 这时候再运行ldconfig 文件,就会发现生成两个连接 文件。

    ln -s libhello.so.0---->libhello.so.0.0.0

    ln -s libhello.so.1----->libhello.so.1.0.0

尽管共享库升级,但是你的程序依旧用的是旧的共享库,并且两个之间不会相互影响。

    问题是如果更新的共享库只是增加一些接口,并没有修改已有的接口,也就是向前兼容。但是这时候它的主版本号却增加1. 如果你的应用程序想调用新的共享库,该怎么办? 简单,只要手工把soname 文件修改,使其指向新的版本就可以。(这时候ldconfig 文件不会帮你做这样的事,因为这时候soname 和real name 的版本号主板本号不一致,只能手动修改)。

  比如: ln -s libhello.so.0 ---> libhello.so.1.0.0

  但是有时候,主版本号增加,接口发生变化,可能向前不兼容。这时候再这样子修改,就会报错,“xx”方法找不到之类的错误。

总结一下,Linux 系统是通过共享库的三个不同名字,来管理共享库的多个版本。 real name 就是共享库的实际文件名字,soname 就是共享库加载时的用的文件名。在生成共享库的时候,编译器将soname 绑定到共享库的文件头里,二者关联起来。 在应用程序引用共享库时,其通过link name 来完成,link时将按照系统指定的目录去搜索link名字找到共享库,并将共享库的soname写在应用程序的头文件里。当应用程序加载共享库时,就会通过soname在系统指定的目录(path or LD_LIBRARY)去寻找共享库。

当共享库升级时,分为两种。一种是主板本不变,升级小版本和build 号。在这种情况下,系统会通过更新soname( ldconfig 来维护),来使用新的版本号。这中情况下,旧版本就没有用,可以删掉。

另外一种是主版本升级,其意味着库的接口发生变化,当然,这时候不能覆盖已有的soname。系统通过增加一个soname(ldconfig -p 里面增加一项),使得新旧版本同时存在。原有的应用程序在加载时,还是根据自己头文件的旧soname 去寻找老的库文件。

5.如果编译的时候没有指定,共享库的soname,会怎么样?

  这是一个trick 的地方。第一系统将会在生成库的时候,就没有soname放到库的头里面。从而应用程序连接时候,就把linkname 放到应用程序依赖库里面。或者换句话说就是,soname这时候不带版本号。 有时候有人直接利用这点来升级应用程序,比如,新版本的库,直接拷贝到系统目录下,就会覆盖掉已经存在的旧的库文件,直接升级。 这个给程序员很大程度的便利性,如果一步小心,就会调到类似windows的Dll hell 陷阱里面。建议不要这样做。
=================================================================================================

Makefile有一句:
DYLIB_MAKE_CMD=$(CC) -shared -Wl,-soname,$(DYLIB_MINOR_NAME) -o $(DYLIBNAME) $(LDFLAGS)
编译下看看输出:
[hiredis]# make clean
rm -rf libhiredis.so libhiredis.a hiredis-test examples/hiredis-example* *.o *.gcda *.gcno *.gcov
[hiredis]# make
cc -std=c99 -pedantic -c -O3 -fPIC  -Wall -W -Wstrict-prototypes -Wwrite-strings -g -ggdb  net.c
cc -std=c99 -pedantic -c -O3 -fPIC  -Wall -W -Wstrict-prototypes -Wwrite-strings -g -ggdb  hiredis.c
cc -std=c99 -pedantic -c -O3 -fPIC  -Wall -W -Wstrict-prototypes -Wwrite-strings -g -ggdb  sds.c
cc -std=c99 -pedantic -c -O3 -fPIC  -Wall -W -Wstrict-prototypes -Wwrite-strings -g -ggdb  async.c
cc -shared -Wl,-soname,libhiredis.so.0.11 -o libhiredis.so  net.o hiredis.o sds.o async.o
静态编译:
ar rcs libhiredis.a net.o hiredis.o sds.o async.o
一)这个/home/test/rpmbuild/BUILD/ngx_http_monitor_module-2.2.0/hiredis 目录下面也并没有:
ls libhiredis.so.0.11
ls: cannot access libhiredis.so.0.11: No such file or directory
readelf -d libhiredis.so
静态就是纯静态的:
ldd libhiredis.a
ldd: warning: you do not have execution permission for `./libhiredis.a'
        not a dynamic executable

Dynamic section at offset 0xa7f0 contains 21 entries:
  Tag        Type                         Name/Value
0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
0x000000000000000e (SONAME)             Library soname: [libhiredis.so.0.11]   <===就是这个就是-soname,libhiredis.so.0.11编译进去的。

二)Nginx启动后,并找不到这个:
ldd /usr/local/nginx/sbin/nginx
        libhiredis.so.0.11 => not found
Starting nginx: /usr/local/nginx/sbin/nginx: error while loading shared libraries: libhiredis.so.0.11: cannot open shared object file: No such file or directory

=============================================================================================


怎么样实现把共享库的soname 提取出来,写在自己的共享库的头文件里面?
第二个是动态库的soname( Short for shared object name),依赖该shared library的应用程序中记录了它的soname,所以应用程序加载该shared library的时候,其寻找共享库用的soname文件名。其格式为

                           lib + math+.so + ( major version number)

它是一个指向名字为real name的shared library的软链接。

  当升级主版本时,共享库的soname 就会加1.比如libhello.so.0.0.0 变为 libhello.so.1.0.0. 这时候再运行ldconfig 文件,就会发现生成两个连接 文件。
    ln -s libhello.so.0---->libhello.so.0.0.0
    ln -s libhello.so.1----->libhello.so.1.0.0
尽管共享库升级,但是你的程序依旧用的是旧的共享库,并且两个之间不会相互影响。

    问题是如果更新的共享库只是增加一些接口,并没有修改已有的接口,也就是向前兼容。但是这时候它的主版本号却增加1. 如果你的应用程序想调用新的共享库,该怎么办? 简单,只要手工把soname 文件修改,使其指向新的版本就可以。(这时候ldconfig 文件不会帮你做这样的事,因为这时候soname 和real name 的版本号主板本号不一致,只能手动修改)。
  比如: ln -s libhello.so.0 ---> libhello.so.1.0.0
  但是有时候,主版本号增加,接口发生变化,可能向前不兼容。这时候再这样子修改,就会报错,“xx”方法找不到之类的错误。

这就是接下来要介绍的第三个共享库的名字,link name,顾名思义,就是在编译过程,link 阶段用的文件名。 其将soname 和real name 关联起来。
第三个名字,共享库的连接名(link name),是专门为build 阶段连接而用的名字。这个名字就是lib + math +.so ,比如libmath.so。其是不带任何版本信息的。在共享库编译过程中,连接(link) 阶段,编译器将生成一个共享库及real name,同时将共享库的soname,写在共享库文件里的文件头里面。可以用命令 readelf -d sharelibrary 去查看。

在应用程序引用共享库时,其会用到共享库的link name。在应用程序的link阶段,其通过link名字找到动态库,并且把共享库的soname 提取出来,写在自己的共享库的头文件里面。当应用程序加载时就会通过soname 去给定的路径下寻找该共享库。
参考:
http://blog.163.com/kefeng_1984/blog/static/166615272014714114141296/
http://blog.chinaunix.net/uid-23592843-id-223539.html

阅读全文
背景:奶奶的,回重庆的票没着落,回的来票倒是搞了,难不成真得坐高铁?有没有必要拉一100M带宽靠近点服务器好,呵呵。
重庆至北京高铁元旦首发 商务座票价2383...  
6小时前 重庆至北京高铁元旦首发 票价767.5元...  
12小时前 重庆至北京高铁元旦首发 票价767.5元...  
背景:当今中国,对知识产权的保护,我扯下淡吧,还是不够,但目前来说,中国人民的确是没钱,买点便宜的,也就罢了,人们已经很艰难,就不要拆穿,这位仁兄非要这样写,于是就写出了这样的文章了,真是....叫好。
   作者:水木然

   其实,拉动中国经济增长的三驾马车是这样的:

一、抄袭
阅读全文
SQLite3是一个极轻型的独立的无服务器的SQL数据库引擎。

你不需要做任何的配置来使其工作。所有你需要的就是安装它并开始使用它。

既然是无服务器的,它被用在很多你所使用的著名的软件中,甚至你可能并不知道那些软件正在使用它。看看下面的例子所有的大公司正在使用SQLiete.PUP编程语言内嵌了SQLite数据库于其中。

如果你从来没有使用过SQLite,按照下面的文章中所提到的步骤安装在Linux上,并且创建了一个例子数据库。


下载SQLite3源代码
去SQLite下载页面,并点击“sqlite-autoconf-3070603.tar.gz”(在源代码部分),并下载到你的系统中。或者使用wget直接从服务器下载就像下面。



安装 SQLite3

Uncompress the tar.gz file and install SQLite3 as shown below.

解压tar.gz文件并像下面所示安装

tar xvfz sqlite-autoconf-3080704.tar.gz
cd sqlite-autoconf-3080704
./configure
make
make install

make安装命令后会有以下的输出。

test -z "/usr/local/bin" || mkdir -p -- "/usr/local/bin"
  ./libtool --mode=install /usr/bin/install -c sqlite3 /usr/local/bin/sqlite3
/usr/bin/install -c .libs/sqlite3 /usr/local/bin/sqlite3
test -z "/usr/local/include" || mkdir -p -- "/usr/local/include"
/usr/bin/install -c -m 644 'sqlite3.h' '/usr/local/include/sqlite3.h'
/usr/bin/install -c -m 644 'sqlite3ext.h' '/usr/local/include/sqlite3ext.h'
test -z "/usr/local/share/man/man1" || mkdir -p -- "/usr/local/share/man/man1"
/usr/bin/install -c -m 644 './sqlite3.1' '/usr/local/share/man/man1/sqlite3.1'
test -z "/usr/local/lib/pkgconfig" || mkdir -p -- "/usr/local/lib/pkgconfig"
/usr/bin/install -c -m 644 'sqlite3.pc' '/usr/local/lib/pkgconfig/sqlite3.pc'

提示:如果你对mysql数据库有兴趣,你也可以安装在你的系统中。

摘自:http://blog.csdn.net/qianguozheng/article/details/6731928


在redhat安装gearman,在make的时候,报错,怎么解决的办法:
[root@test gearmand-1.1.12]# make
make -j9  all-am
make[1]: Entering directory `/home/xiangdong/software/gearmand-1.1.12'
  CXX      libgearman-server/plugins/queue/sqlite/libgearman_server_libgearman_server_la-instance.lo
libgearman-server/plugins/queue/sqlite/instance.cc: In member function 'bool gearmand::queue::Instance::_sqlite_prepare(const std::string&, sqlite3_stmt**)':
libgearman-server/plugins/queue/sqlite/instance.cc:125: error: 'sqlite3_prepare_v2' was not declared in this scope
libgearman-server/plugins/queue/sqlite/instance.cc: In member function 'gearmand_error_t gearmand::queue::Instance::init()':
libgearman-server/plugins/queue/sqlite/instance.cc:224: error: 'SQLITE_OPEN_READWRITE' was not declared in this scope
libgearman-server/plugins/queue/sqlite/instance.cc:224: error: 'SQLITE_OPEN_CREATE' was not declared in this scope
libgearman-server/plugins/queue/sqlite/instance.cc:224: error: 'sqlite3_open_v2' was not declared in this scope
make[1]: *** [libgearman-server/plugins/queue/sqlite/libgearman_server_libgearman_server_la-instance.lo] Error 1
make[1]: Leaving directory `/home/xiangdong/software/gearmand-1.1.12'
make: *** [all] Error 2

删除了系统原带的sqlite3 ,到官网上下一个源码,重新编译安装sqlite3。

如:
把sqlite3安装到 /usr/local/sqlite3
tar zxf sqlite3.xxxx.tar.gz
cd sqlite.3.xxxx
./configura --prefix=/usr/local/sqlite3
make && make install
cd ..

最后在编译Gearman时带上 --with-sqlite3=/usr/local/sqlite3,告诉编译器应该使用这个新的sqlite即可。

实践如下:


来自:http://zhidao.baidu.com/question/531552126.html
背景:PHP的gearman需要这Lib库,才能编译得过,做一些多任务分发时需要gearman的PHP扩展。
Download: http://sourceforge.net/projects/boost/?source=typ_redirect
阅读全文
背景:自己整个T60P的电脑一直想折腾到4G,各种折腾硬是没有折腾上得去。啥ReadyFor4GB 突破 32 位 Windows 7 Vista 内存 4G 限制,啥利用富裕RAM提高系统运行速度的两种途径——RAMDRIVE和SMARTDRV。都无效果,最后一查,还是硬件没有支持,啥软件方法都白扯,

   前一段时间T60p里面有条1G的内存坏了,机器总蓝屏,于是买了一条2G的换上,本子有3G内存了,上周同事从美国又给我带来一条2G的,于是把另一条1G的也换下来了,就有了4G,可是Vista系统只认到3G,于是升级BIOS,换操作系统为2003,2008,强行启用PAE,都没用,只能认到3G,到网上搜索,各种说法不一。最后还是在联想官网找到了答案,T60p不支持4G内存,主板决定的,安装什么操作系统都没戏,痛苦啊。。。。。


Memory 256M,512MB,1GB or 2GB and supports up to 4GB maximum memory
Note:Only 64-bit operating systems support more than 3GB of system memory(RAM).Inter Chipsets 945GM and945PM do not support more than 3GB system memory(RAM),even when a 64-bit operatiing system is installed.

来自:http://simon.blog.51cto.com/80/83561/



②关于T60p能不能支持4G以上内存的问题
我谷歌到的大部分答案,都是简单的“可以”。
导致了内存价钱便宜时,伤害了那些8G/16G用户……
理论状态32位的CPU,寻址2的32次方=4,294,967,296=4,294,967K=4,294M=4G
因此,以T2700为首T2字头的32位CPU群,4G是极限!且系统里见到3.5之类也是正常的。
而T7字头为64位的CPU,4G以上(128G以下)自然就木问题了!
当然,操作系统也的用64位的,否则还是那个“32位限制”的根本问题。
UPDATE: 多谢手握真相的网友,官方答复因945PM无法支持Memory Remapping!
因此T60p 硬件可以上4G,但实际最多只能用3G!
摘自:http://blog.sina.com.cn/s/blog_5921fa08010170yq.html


T60p安装SSD后出现windows7 卡(死)现象,与AHCI关系不大!
(后面会详述解决方案):
http://blog.sina.com.cn/s/blog_5921fa08010170yq.html

终于忍不住将t60p的风扇换成T500的风扇了:
http://www.nb591.com/thread-102982-1-1.html
http://www.wendangdaquan.com/Wdshow.asp?id=879ee2294b73f242336c5fe0
购买地址:https://item.taobao.com/item.htm?spm=a1z10.3-c.w4002-3869566946.40.1UnP1i&id=8524574266
安装地址:http://www.docin.com/p-394979668.html
        每个人都知道,肥从口出。减肥的根本就是要控制食量。控制食量不是叫你不食,而是少吃。同时要从你吃的东西,改变你的饮食习惯和体内代谢。 促进代谢怎么做健康?
       下面是我一天的食谱
       早上:2杯温开水(可以清肠,调理代谢作用)豆浆2杯(一定是无糖新鲜豆浆),麦片1大碗(普通超市买的即食原味麦片就好。一定在吃完豆浆后才吃)如果感觉还饿可以多吃个苹果 中午:正常吃饭(宁可吃多点菜也别多吃点饭吗,饭一小碗就好。最好选鸡肉,鱼吃。)吃完后一定记得喝杯茶。晚餐:正常吃饭(宁可吃多点菜也别多吃点饭吗,饭一小碗就好。最好选鸡肉,鱼吃。)吃完后喝杯普洱。记得8点后一定不要进食。 除此还要多运动。

       节食没有减下来的,不仅效果慢,而且肯定会反弹。那我到底是怎么瘦的呢?呵呵,其实重点在我每天午饭后喝的茶上,其实那不是一般的绿茶或是潽尔茶,而是一款具有更强、更专业的瘦身效果的饮料,名字叫做大肚子减肥茶。我就是靠着喝这款饮料来为身体补充瘦素和清除自由基,所以才健健康康瘦下来一年不反弹的。  大肚子减肥茶都合适什么人群呢?>>>  
       减肥小贴士
     (1)饭后一定要养成喝茶的习惯(茶可以减肥可以养生,也可以去油脂)
     (2)能站别坐,能坐别躺。多运动
     (3)早睡早起,最好12点前睡,早上一定要养成喝两杯水的习惯。喝水可以调节代谢,代谢好一定会廋,何为代谢好--每天起来都可以拉一坨漂亮的便便!
背景:i++还是++i这个问题,我为什么记下了,又忘记了,我觉得这是一个哲学问题。
这是一个医学问题,这是一个物理问题:

Firefox下,打开一个空白页面,按下:Shift+F4,调出Js调试工具:


先后是:
1
2
2
2
原因如下:
a= i++;
则相当于  a=i;i=i+1;   //alert i++ 时:相当于a=i,还是原值1。后面再alerti时相当于i=i+1了等于2.
a=++i;
则相当于  i=i+1;a=i;// alert ++i 时,相当于前面的i=i+1,所以就等于2了,而接着再alert i 时还是2.
________________________________________________________
都是i=i+1的意思,区别在于i++是i先不自加,在语句完后自加,++i先自加;
列如a=1+i++;i本来为1的话,这里a=1+1;语句完后i才加1为2;
a=1+++i的话就先i=i+1;i=2.然后a=i+1,a=3

直接使用看不出区别,都是变量i加1
在赋值时才能进行区别,
如:
y=i++  // y的值为i (先引用,后运算)
y=++i  // y的值为i+1的结果 (先运算,后引用)

++i是在使用i之前先使i的值加1
i++是在使用i之后,使i的值加1
分页: 63/338 第一页 上页 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 下页 最后页 [ 显示模式: 摘要 | 列表 ]