D-Bus
D-Bus 也是一个用于进程间通信的框架。
简单介绍一下如何编写一个helloworld通信例子。
0. 下载源码
http://www.freedesktop.org/wiki/Software/dbus#Download.
1. ./configure
这时候可能会出现问题:
configure: error: Could not find expat.h, check config.log for failed attempts
可以通过
sudo apt-get install libexpat1-dev
来解决
2. make
3. make install
其中可能遇到的编译问题
1. fatal error: dbus/dbus.h: No such file or directory
把/usr/local/include/dbus-1.0/dbus/拷贝到/usr/include/dbus
2. fatal error: dbus/dbus-arch-deps.h: No such file or directory
把/usr/local/lib/dbus-1.0/include/dbus/dbus-arch-deps.h拷贝到/usr/include/dbus
3. 链接错误 collect2: ld returned 1 exit status
添加链接选项 -l dbus-1
测试代码
服务端接收消息
/* server.c */ #include <dbus/dbus.h> #include <stdbool.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> static DBusHandlerResult filter_func(DBusConnection *connection, DBusMessage *message, void *usr_data) { dbus_bool_t handled = false; char *word = NULL; DBusError dberr; if (dbus_message_is_signal(message, "client.signal.Type", "Test")) { dbus_error_init(&dberr); dbus_message_get_args(message, &dberr, DBUS_TYPE_STRING, &word, DBUS_TYPE_INVALID); if (dbus_error_is_set(&dberr)) { dbus_error_free(&dberr); } else { printf("receive message %s\n", word); handled = true; } } return (handled ? DBUS_HANDLER_RESULT_HANDLED : DBUS_HANDLER_RESULT_NOT_YET_HANDLED); } int main(int argc, char *argv[]) { DBusError dberr; DBusConnection *dbconn; dbus_error_init(&dberr); dbconn = dbus_bus_get(DBUS_BUS_SESSION, &dberr); if (dbus_error_is_set(&dberr)) { dbus_error_free(&dberr); return -1; } if (!dbus_connection_add_filter(dbconn, filter_func, NULL, NULL)) { return -1; } dbus_bus_add_match(dbconn, "type='signal',interface='client.signal.Type'", &dberr); if (dbus_error_is_set(&dberr)) { dbus_error_free(&dberr); return -1; } while(dbus_connection_read_write_dispatch(dbconn, -1)) { /* loop */ } return 0; }
#include <dbus/dbus.h> #include <stdbool.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> int db_send(DBusConnection *dbconn) { DBusMessage *dbmsg; char *word; int i; dbmsg = dbus_message_new_signal("/client/signal/Object", // object name of the signal "client.signal.Type", // interface name of the signal "Test"); // name of the signal if (!dbmsg) { return -1; } word = "hello world"; if (!dbus_message_append_args(dbmsg, DBUS_TYPE_STRING, &word, DBUS_TYPE_INVALID)) { return -1; } if (!dbus_connection_send(dbconn, dbmsg, NULL)) { return -1; } dbus_connection_flush(dbconn); printf("send message %s\n", word); dbus_message_unref(dbmsg); return 0; } int main(int argc, char *argv[]) { DBusError dberr; DBusConnection *dbconn; int i; dbus_error_init(&dberr); dbconn = dbus_bus_get(DBUS_BUS_SESSION, &dberr); if (dbus_error_is_set(&dberr)) { return -1; } db_send(dbconn); dbus_connection_unref(dbconn); return 0; }
内核模块编译
Makefile文件
# 内核文件名称 obj-m := hello.o # 内核源码地址 KDIR := /lib/modules/$(shell uname -r)/build # 当前路径 PWD = $(shell pwd) default: make -C $(KDIR) SUBDIRS=$(PWD) modules clean: rm rf Module.symvers *.o *.mod.c *.cmd .tmp_versions
源文件hello.c
#include <linux/module.h> #include <linux/init.h> static int hello_init(void) { printk("helloworld init\n"); return 0; } static void hello_exit(void) { printk("helloworld exit\n"); return; } module_init(hello_init); module_exit(hello_exit);
然后执行make 生成内核模块hello.ko
加载模块 insmod hello.ko
卸载模块 rmmod hello.ko
查看模块 lsmod
Module Size Used by hello 12496 0
Used by表示这个模块被引用的次数,只有为0的时候才可以卸载模块
内核使用printk打印信息,可以用命令dmesg查看log
[ 412.605328] helloworld init [ 433.266742] helloworld exit
找到一个很详细的内核模块加载的文章
/user_files/lazycat/File/《深入Linux设备驱动程序内核机制》第1章 内核模块.pdf
unix domain socket相关
1.关于SIGPIPE信号
今天测试代码发现,当已经建立了Stream连接的DomainSocket的服务端进程终止后,客户端进程调用send函数导致客户端进程也退出了的情况。
上网搜了一下,发现是客户端进程收到了一个SIGPIPE信号,信号默认的执行动作是终止退出。
解决办法应该是使用
signal(SIGPIPE, SIG_IGN);
忽略SIGPIPE信号。
这样在断开连接后,还继续调用send的情况下,会返回-1,错误号为EPIPE(Broken pipe)。
PS:在recv(sock, ...) 得到返回值为0的时候表示连接断开,这时候应该调用close(sock)来保证后续不会出现问题。
相关链接:
http://www.cppblog.com/elva/archive/2008/09/10/61544.html
http://stackoverflow.com/questions/108183/how-to-prevent-sigpipes-or-handle-them-properly
gdb结合coredump定位崩溃进程
Linux环境下经常遇到某个进程挂掉而找不到原因,我们可以通过生成core file文件加上gdb来定位。
ulimit -c unlimited
这样便把core file的大小设置为了无限大,同时也可以使用数字来替代unlimited,对core file的上限值做更精确的设定。
echo "pattern" > /proc/sys/kernel/core_pattern
并且只有超级用户可以修改这两个文件。
%p: 相当于<pid>
%u: 相当于<uid>
%g: 相当于<gid>
%s: 相当于导致dump的信号的数字
%t: 相当于dump的时间
%h: 相当于hostname
%e: 相当于执行文件的名称
#include <stdio.h> int func(int *p) { *p = 0; } int main() { func(NULL); return 0; }
Segmentation fault (core dumped)
#0 0x080483ba in func ()
如何定位到行?
#0 0x080483ba in func (p=0x0) at a.c:5
5 *p = 0;
SIGQUIT:终端退出符
SIGILL:非法硬件指令
SIGTRAP:平台相关的硬件错误,现在多用在实现调试时的断点
SIGBUS:与平台相关的硬件错误,一般是内存错误
SIGABRT:调用abort函数时产生此信号,进程异常终止
SIGFPE:算术异常
SIGSEGV:segment violation,无效内存引用
SIGXCPU:超过了cpu使用资源限制(setrlimit)
SIGXFSZ:超过了文件长度限制(setrlimit)
SIGSYS:无效的系统调用