linux小程序

7月20日
例程十八_GUI_pygtk

Ø       功能

l          python gtk 入门,做最简单的界面:含普通窗口,按扭,回调函数,窗口关闭时退出的程序

Ø       知识点

l          python 是解释性语言,无需编译,即可直接执行

l          python 有类定义,结构清晰 (this->self) ,没声明,直接实现

l          {} 来分界类和函数,只用缩进,所以不能使用 tab 在代码中缩进

Ø       示例

l          环境
ubuntu 8.04 系统,安装 python 及相关工具(如果安装不全,运行程序时会有提示,按提示安装缺少的包即可)

l          源码

#!/usr/bin/env python

 

import pygtk // 导入必要的库

pygtk.require('2.0')

import gtk // 导入必要的库

 

class test:          // 主要的类声明,以下缩进后的都是类的实现

    def test(self, widget, data=None): // 定义按钮按下的响应函数

        print "Hello"     // 打印hello

 

    def destroy(self, widget, data=None): // 定义窗口销毁的响应函数

        gtk.main_quit() // 退出应用

       

    def __init__(self):      // 构造函数

        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)         // 建立窗口

        self.window.connect("destroy", self.destroy)                  // 连接窗口销毁事件及其响应函数

        self.window.show()      // 显示窗口

 

        self.button = gtk.Button("testme")      // 建立按钮

        self.button.connect("clicked", self.test, None)      // 连接按钮及其点击的响应函数

        self.button.show()        // 显示按钮

        self.window.add(self.button)         // 把按件加入窗口

 

    def main(self): // 定义类中的main 函数

        gtk.main() 

 

if __name__ == "__main__":    // 主函数

    testme = test()   // 建立一个test 类的实例,此时调用构造函数

    testme.main() // 运行类中的 main 函数

l          执行
$ chmod 755 ./a.py
$ ./a.py


$ python a.py
即可看到界面

Ø       参考

l          python example
http://www.andrew.cmu.edu/user/skey/research_prev/checker/working%20now/gui/pygtk2tutorial/pygtk2tutorial/ch-GettingStarted.html#sec-HelloWorld

l          完整例程下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/GUI/case%7C_pythongtk.tgz
下载 case_pythongtk.tgz

5月20日
例程十七_IPC_pipe

Ø       功能

l          进程间通讯 (IPC)

l          常用于数据流的传输

Ø       知识点

l          管道文件是一种特殊的文件,通常一个进程在一端写中,另一进程在另一端读出数据,从而达到进程间通讯

l          注意问题

u        管道文件不占磁盘空间

u        管道有缓冲区,可以设置其大小

u        由于管道中数据是流式的,所以可能引起一次写入,多次读出,或多次写入一次读出的问题,只能通过数据结构设计解决此问题

u        管道读取方式分为阻塞和不阻塞,不阻塞时,读取返回错误值

Ø       示例

l          源码

u        发送方 send.c

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <string.h>

 

#define TMPPIPE "/tmp/tmppipe"       // 管道文件名

 

int main(int argc, char **argv)

{

         int fd;

         char str[256] = "msg...";

 

         if (argc > 1)

                   strcpy(str, argv[1]);

 

         if ((fd = open(TMPPIPE, O_WRONLY)) != -1)               // 以写方式打开管道文件

         {

                   printf("send: %s/n", str);

                   write(fd, str, strlen(str) + 1);       // 写数据

                   close(fd);

         }

}

u        接收方 recv.c

#include <stdio.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <string.h>

 

#define TMPPIPE "/tmp/tmppipe"

 

int main(int argc, char **argv)

{

         int fd;

         char str[256];

 

         unlink(TMPPIPE);    // 删除可能存在的原管道文件

         mkfifo(TMPPIPE, 0666);    // 建立管道文件

        

         if ((fd = open(TMPPIPE, O_RDONLY)) != -1)      // 以读方式打开管道文件

         {

                   read(fd, str, 256);        // 从管道中读取数据

                   printf("recv: %s/n", str);

                   close(fd);

         }

}

l          编译

gcc send.c -o send

gcc recv.c -o recv

l          执行结果
在一个终端运行 recv 等待接收数据变化
另一个终端运行 send ,参数是要发送的字串(注意 send, recv 使用同一用户)
此时在 recv 终端看到收到发送过来的字串

Ø       参考

l          源码下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/IPC/case%7C_pipe.tgz

 

例程十六_IPC_msg

Ø       功能

l          进程间通讯 (IPC)

l          具有较强的实时性

Ø       知识点

l          进程间相互发送信息,通常一方等待消息,另一方发送时,它立即收到

l          注意 send recv 信息时的长度参数是不含类型长度的

Ø       示例

l          源码

u        发送方 send.c

#include <sys/ipc.h>

#include <sys/msg.h>

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

 

typedef struct

{

         long type; // message type

         char data[256];

} msg_info;

 

int main(int argc, char **argv)

{

         int msg_id;

         int msg_type = 8;

         msg_info info;

    key_t key;

         char str[256] = "msg...";

 

         if (argc > 1)

                   strcpy(str, argv[1]);

 

         if ((key = ftok("/home", 1)) == -1)      // 生成 key ,第一个参数是某个路径(有时候用程序名),第二个参数一般指开的第几个共享内存

                   perror("ftok"), exit(-1);

         if ((msg_id = msgget(key, IPC_CREAT | 0660)) == -1)  // 打开共享内存句柄

                   perror("msgget"), exit(-1);

 

         info.type = msg_type;

         strcpy(info.data, str);

 

         if (msgsnd(msg_id, &info, sizeof(msg_info) - sizeof(long), 0) == -1)      // 发送信息,注意写入长度不含 type 长度

                   perror("msgsnd"), exit(-1);

         else

                   printf("send: %s/n", info.data);

 

         return 0;

}

u        接收方 recv.c

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/msg.h>

#include <string.h>

#include <stdlib.h>

#include <stdio.h>

 

typedef struct

{

         long type; // message type

         char data[256];

} msg_info;

 

int main(int argc, char *argv[])

{

         int msg_id;

         int msg_type = 8;

    key_t key;

         msg_info info;

 

         if ((key = ftok("/home", 1)) == -1)

                   perror("ftok"), exit(-1);

         if ((msg_id = msgget(key, IPC_CREAT | 0660)) == -1)

                   perror("msgget"), exit(-1);

         if (msgrcv(msg_id, &info, sizeof(msg_info) - sizeof(long), msg_type, 0) == -1)                // 读取信息,注意读取长度不含 type 长度

                   perror("msgrecv"), exit(-1);

         else

                   printf("recv: %s/n", info.data);

         return 0;

}

l          编译

gcc send.c -o send

gcc recv.c -o recv

l          执行结果
在一个终端运行 recv 等待接收数据变化
另一个终端运行 send ,参数是要发送的字串
此时在 recv 终端看到收到发送过来的字串

Ø       参考

l          源码下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/IPC/case%7C_msg.tgz

 

例程十五_IPC_shm

Ø       功能

l          进程间通讯 (IPC)

l          通常用于进程间共享和交换数据

Ø       知识点

l          两个不同进程通过 key 共享同一内存

Ø       示例

l          源码

u        发送方 send.c

#include <sys/ipc.h>

#include <sys/msg.h>

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

 

int main(int argc, char **argv)

{

         int mem_id;

    key_t key;

         char str[256] = "msg...";

         void *mem_addr;

 

         if (argc > 1)

                   strcpy(str, argv[1]);

 

         if ((key = ftok("/usr", 1)) == -1) // 生成 key ,第一个参数是某个路径(有时候用程序名),第二个参数一般指开的第几个共享内存

                   perror("ftok"), exit(-1);

         if ((mem_id = shmget(key, 1024, IPC_CREAT)) == -1) // 打开 / 开辟共享内存

                   perror("shmget"), exit(-1);

         if ((mem_addr = (void*)shmat(mem_id, 0, 0)) == (void*)(-1))         // 映射到变量

                   perror("shmat"), exit(-1);

 

         memcpy(mem_addr, str, 256);     // 向共享内存中写数据

         printf("send: %s/n", str);

 

         return 0;

}

u        接收方 recv.c

#include <sys/ipc.h>

#include <sys/msg.h>

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

 

int main(int argc, char *argv)

{

         int mem_id;

    key_t key;

         char str[256];

         void *mem_addr;

 

         if ((key = ftok("/usr", 1)) == -1)

                   perror("ftok"), exit(-1);

         if ((mem_id = shmget(key, 1024, IPC_CREAT)) == -1)

                   perror("shmget"), exit(-1);

         if ((mem_addr = (void*)shmat(mem_id, 0, 0)) == (void*)(-1))

                   perror("shmat"), exit(-1);

 

         memcpy(str, mem_addr, 256);              // 从共享内存中读数据

         printf("recv: %s/n", str);

 

         shmctl(mem_id, IPC_RMID, NULL);  // 删除共享内存

         return 0;

}

l          编译

gcc send.c -o send

gcc recv.c -o recv

l          执行结果
在终端执行 send 参数是你想发送的信息 ( 也可不带参,发送 msg…)
在终端执行 recv ,可以看到你之前发送的信息

Ø       参考

l          源码下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/IPC/case%7C_shm.tgz

 

例程十四_IPC_mmap

Ø       功能

l          进程间通讯 (IPC)

l          实现简单,用于数据共享

Ø       知识点

l          mmap 将某个文件内容映射到内存中,对该内存区(变量)存取即直接对该文件内容读写,两个进程映射同一文件,实现内存共享

Ø       示例

l          源码

u        发送方 send.c

#include <sys/types.h>

#include <sys/stat.h>

#include <sys/mman.h>

#include <fcntl.h>

#include <stdio.h>

#include <string.h>

 

#define TMP_MAP_FILE "/tmp/mapfile"   // 被映射的文件

#define TMP_MAP_SIZE 256     // 被映射的文件长度

 

main(int argc, char **argv)

{

         int fd;

         char *p_map;

         char str[256] = "msg...";

 

         if (argc > 1)

                   strcpy(str, argv[1]);

 

         fd = open(TMP_MAP_FILE, O_CREAT | O_RDWR | O_TRUNC, 00777);

         lseek(fd, TMP_MAP_SIZE, SEEK_SET);

         write(fd, "", 1);          // 若文件刚被创建,则长度为 0, 加入空字格,以扩展文件长度

         p_map = (char *) mmap(NULL, TMP_MAP_SIZE, PROT_READ | PROT_WRITE,

                     MAP_SHARED, fd, 0);    // 内存映射, MAP_SHARE 允许其它程序共享

         close(fd);

         strcpy(p_map, str);     // 把内容复制到共享内存中

         munmap(p_map, TMP_MAP_SIZE);   // 解除映射

}

u        接收方 recv.c

#include <sys/types.h>

#include <sys/stat.h>

#include <sys/mman.h>

#include <fcntl.h>

#include <stdio.h>

#include <string.h>

 

#define TMP_MAP_FILE "/tmp/mapfile"

#define TMP_MAP_SIZE 256

 

main(int argc, char **argv)

{

         int fd;

         char *p_map;

 

         fd = open(TMP_MAP_FILE, O_CREAT | O_RDWR, 00777);

         p_map = mmap(NULL, TMP_MAP_SIZE, PROT_READ | PROT_WRITE,  MAP_SHARED, fd, 0);

         printf("recv: %s/n", p_map);

         munmap(p_map, TMP_MAP_SIZE);

}

l          编译

gcc send.c -o send

gcc recv.c -o recv

l          执行结果
在终端执行 send 参数是你想发送的信息 ( 也可不带参,发送 msg…)
在终端执行 recv ,可以看到你之前发送的信息

Ø       参考

l          源码下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/IPC/case%7C_mmap.tgz

 

4月18日
例程十三_GUI_抓背景图

Ø       功能

l          获取当前屏幕的背景(只含背景图)

l          主要用于软件中的特殊效果的图像合成

Ø       知识点

l          根窗口:用户桌面中垫在最下边的特殊窗口,它是背景图所在的窗口,一般由窗口管理器管理

l          背景图是窗口的一个属性,可由用户程序设置和获取

l          gdk 对窗口的操作都是对 X 函数的封装,即都可以 XLib 中找到对应函数实现

l          背景图大小可能与屏幕大小不一致,所以在操作前可能需要叠放和拉伸

Ø       示例

l          源码

#include <gtk/gtk.h>

#include <gdk/gdk.h>

#include <gdk/gdkx.h>

#include <X11/Xatom.h>

#include <gdk-pixbuf/gdk-pixbuf.h>

#include <stdlib.h>

 

int main(int argc, char *argv[])

{

        GdkDisplay *display = NULL;

        GdkScreen *screen = NULL;

        GdkWindow *window = NULL;

        GdkColormap *cmap = NULL;

        GdkPixmap *pixmap = NULL;

        GdkPixbuf *pixbuf = NULL;

        Pixmap *prop_data = NULL;

        GdkAtom prop_type;

        int w, h;

 

        gtk_init(&argc, &argv);

 

        screen = gdk_screen_get_default();    // 获取默认的 screen

        display = gdk_screen_get_display(screen); // 获取 screen 对应的 display

        window = gdk_screen_get_root_window(screen);          // 获取根窗口

        cmap = gdk_screen_get_default_colormap(screen);     // 获取 screen 的色彩表

 

        if (!gdk_property_get(window,    // 获取窗口图片

                                 gdk_atom_intern_static_string

                                 ("_XROOTPMAP_ID"),

                                 gdk_x11_xatom_to_atom(XA_PIXMAP), 0, 10,

                                 FALSE, &prop_type, NULL, NULL,

                                 (guchar **) & prop_data))

                 return -1;

 

        if ((prop_type == GDK_TARGET_PIXMAP) && prop_data && prop_data[0]) {

                 pixmap = gdk_pixmap_foreign_new_for_display(display,

                                                                            prop_data

                                                                            [0]);

                 gdk_drawable_set_colormap(pixmap, cmap);

                 gdk_drawable_get_size(pixmap, &w, &h);  // 获取图片长宽

                 pixbuf =

                     gdk_pixbuf_get_from_drawable(NULL, pixmap, cmap,

                                                         0, 0, 0, 0, w, h); // 获取 pixbuf 数据

                 gdk_pixbuf_save(pixbuf, "bg.jpg", "jpeg", NULL, "quality",

                                    "100", NULL);  // 将图片存为 jpg 格式

                 g_object_unref(pixmap);

                 g_object_unref(pixbuf);

                 free(prop_data);

        }

}

l          编译
g++ main.c -o main ` pkg-config gtk+-2.0 --libs --cflags`

l          执行结果
同目录下生成名为 screen.jpg 的图片文件
注意最好以根用户权限运行此程序
注意如果设背景为单色,而非图片,则无法获取图片

Ø       参考

l          源码下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/GUI/case%7C_getbg.tgz

 

例程十二_GUI_抓屏

Ø       功能

l          获取当前屏幕显示内容(含背景图及各窗口图标的叠加)

l          主要用于抓屏

Ø       知识点

l          根窗口:用户桌面中垫在最下边的特殊窗口,它是背景图所在的窗口,一般由窗口管理器管理

l          使用 gdk_pixbuf_get_from_drawable 函数可抓取任一窗口的当前图像

l          可以修改本程序在抓图前加入 sleep(5) ,则程序可以 5 秒后自动抓图

Ø       示例

l          源码

#include <gtk/gtk.h>

#include <gdk/gdk.h>

#include <gdk/gdkx.h>

 

int main(int argc, char *argv[])

{

        GdkScreen *screen = NULL;

        GdkWindow *window = NULL;

        GdkPixbuf *pixbuf = NULL;

        int w = -1;

        int h = -1;

 

        gtk_init(&argc, &argv);

 

        screen = gdk_screen_get_default();    // 获取默认的 screen

        window = gdk_screen_get_root_window(screen);                   // 获取根窗口

        w = gdk_screen_get_width(screen);    // 取得屏幕长宽

        h = gdk_screen_get_height(screen);

 

        pixbuf =

            gdk_pixbuf_get_from_drawable(NULL, window, NULL,

                                               0, 0, 0, 0, w, h); // 抓图

        gdk_pixbuf_save(pixbuf,

                           "screen.jpg", "jpeg", NULL, "quality", "100",

                           NULL);      // 将图片存为 jpg 格式

        g_object_unref(pixbuf);      //

}

l          编译
g++ main.c -o main ` pkg-config gtk+-2.0 --libs --cflags`

l          执行结果
同目录下生成名为 bg.jpg 的图片文件
注意最好以根用户权限运行此程序

Ø       参考

l          源码下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/GUI/case%7C_screenshots.tgz

 

4月10日
例程十一_GUI_用glade3做gtk界面

Ø       功能

l          使用 glade3 工具生成 gtk 界面

Ø       知识点

l          glade3 glade2 差别
glade2
生成代码,而 glade3 生成 xml 文件

l          如何运行 glade3 生成的 xml 界面
借助 libglade 库读取 xml 文件,并生成控件

Ø       示例

l          用工具画界面
运行工具
$ glade-3

u        建立一个窗口 ( 左侧工具栏 -> 项层 -> 窗口 )

u        放置一个固定容器在窗口中(左侧工具栏 -> 容器 -> 固定的)

u        放置一个铵钮在容器中(左侧工具栏 -> 控制和显示 -> 按钮)

u        保存,名称为 test.glade

l          源码
test3.glade 的同级目录下,编写源码 main.c

#include <gtk/gtk.h>

#include <glade/glade.h>

 

int main(int argc, char **argv)

{

        GladeXML *gxml;

        GtkWidget *window;

 

        gtk_init(&argc, &argv);

        gxml = glade_xml_new("test.glade", NULL, NULL);   // 读取 xml 文件

        window = glade_xml_get_widget(gxml, "window1");   // 获取名为 window1 控件的指针

        g_object_unref(G_OBJECT(gxml));

        gtk_widget_realize(window);

        gtk_widget_show(window);

        gtk_main();

 

        return 0;

}

l          编译
gcc main.c -o main `pkg-config --libs --cflags gtk+-2.0 libglade-2.0`

l          执行结果
./main
显示 gtk 建立的窗口

Ø       参考

l          程序下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/case%7C_glade3.tgz

3月29日
例程之十_GUI_建立X窗口

Ø       功能

l          X 函数直接建立窗口

l          通过此例程了解 X 窗体建立的过程,以及作为简单测试程序的雉形

Ø       知识点

l          XOpenDisplay
参数为 NULL ,说要取得默认的 display

l          XCreateWindow
建立 XWindow

l          XMapWindow
显示 XWindow 相当于其它 GUI 中的 show 函数

l          XFlush
使之前的操作立即生效

Ø       示例

l          源码

#include <stdio.h>

#include <X11/Xlib.h>

#include <X11/Xutil.h>

 

main()

{

        Display *display;

        Window window;

        XSetWindowAttributes attr;

       

        display = XOpenDisplay(NULL);         // 取默认的 display

        window = XCreateWindow(display, XDefaultRootWindow(display),      // 建立窗口

                   100, 100, 300, 300, 2, XDefaultDepth(display, 0),

                   InputOutput, CopyFromParent, CWBackPixel, &attr);

        XStoreName(display, window, "my test!"); // 设置窗口 title

        XMapWindow(display, window); // 显示窗口( show

        XFlush(display);        // 使以上动作立即生效

 

        getchar();           // 等待用户输入

 

        XDestroyWindow(display, window);    // 销毁窗口

        XFlush(display);

        XCloseDisplay(display);    // 关闭 display

}

l          编译
gcc -o main main.c -L/usr/X11R6/lib -lX11

l          执行结果
在一个终端运行 ./main ,即可看到弹出窗口
在该终端再输入一个字符回车,窗口关闭

Ø       参考

l          代码下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/case%7C_xwin.tgz

l          详细资料
http://fanqiang.chinaunix.net/a4/b8/20010601/220800315.html

 

3月24日
例程之九_GUI_获取窗口的进程PID

Ø       功能

l          获取窗口所在进程的 PID

Ø       知识点

l          得到默认的 display 指针: XOpenDisplay

l          通过字串取对应的 AtomID XInternAtom

l          获取窗的某一属性: XGetWindowProperty

Ø       示例

l          源码

#include <X11/Xlib.h>

#include <X11/Xatom.h>

#include <stdio.h>

#include <string.h>

 

#define MAX_PROPERTY_VALUE_LEN 4096    // 取得属性值最大长度

 

int main(int argc, char **argv)

{

        Display *disp = XOpenDisplay(NULL);       // 获取默认的 display 指针

        Window win = NULL;

        int ret = -1;

        Atom xa_prop_name;

        Atom xa_ret_type;

        int ret_format;

        unsigned long ret_nitems;

        unsigned long ret_bytes_after;

        unsigned long tmp_size;

        unsigned char *ret_prop;

        int id;

 

        if (argc < 2)

        {

                 printf("please input windowID, such as: ./main 0x240001e (use command xwininfo)/n");

                 return -1;

        }

 

        ret = sscanf(argv[1], "0x%0x", &win);         // 从程序参数中获取 xwindow id

        if (ret < 1)

        {

                 printf("please input windowID, such as: ./main 0x240001e (use command xwininfo)/n");

                 return -1;

        }

 

        printf("xwindow id: 0x%0x/n", win);

 

        xa_prop_name = XInternAtom(disp, "_NET_WM_PID", False);  // 取对应字串的 AtomID

 

        if (XGetWindowProperty(disp, win, xa_prop_name, 0,           // 获取窗口属性

                                    MAX_PROPERTY_VALUE_LEN / 4,

                                    False, XA_CARDINAL, &xa_ret_type,         // XA_CARDINAL 为数值类型

                                    &ret_format, &ret_nitems, &ret_bytes_after,

                                    &ret_prop) != Success)       // 后五个参数是返回值

        {

                 printf("Cannot get %s property./n", "_NET_WM_PID");

                 return NULL;

        }

        else

        {

                 memcpy(&id, ret_prop, 4); // 类型传换

                 printf("window pid: %d/n", id);

        }

}

l          编译
$ g++ main.cpp -o main ` pkg-config glib-2.0 --libs --cflags` -lX11

l          执行结果

u        在一个终端打开一个带窗口界面的程序

u        使用以下命令获得窗口的 xwindow id
$ xwininfo |grep “Window id”
运行命令后用鼠标点击程序窗口

u        运行我们编写的程序,并将十六进程的 xwindow id 作为参数传给程序
$ ./main 0x240001e

Ø       参考

l          程序下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/case%7C_x11%7C_pid.tgz

 

3月21日
例程之八_IPC_socket_tcp

Ø       功能

l          进程间通讯 (IPC)

Ø       知识点

l          通讯的实现:通过 socket TCP 连接实现, C/S 架构,发送方为 client 端,接收端为 server 端, server 打开某个端口等待连接, client 连接 server ,以实现通讯和传输数据

l          通讯需要用户有足够的权限

l          通讯双方可以互传数据,但实现相对于其它通讯方式来说比较复杂

Ø       示例

l          源码

u        发送方 send.c

#include <string.h>

#include <stdio.h>

#include <sys/socket.h>

#include <netinet/in.h>

 

#define MSG_PORT 5432 // socket 端口

 

int open_socket()       // 打开 socket 端口

{

         int sfd = -1;

         int ret = -1;

         struct sockaddr_in addr;

 

         sfd = socket(AF_INET, SOCK_STREAM, 0);       // 建立 TCP 连接

         if (sfd <= 0)

                   return -1;

 

         memset(&addr, 0, sizeof(addr));

         addr.sin_family = AF_INET;

         addr.sin_addr.s_addr = 0;

         addr.sin_port = htons(MSG_PORT);

 

         ret = connect(sfd, (struct sockaddr *) &addr, sizeof(addr));   // 连接

         if (ret >= 0)

                   return sfd;

         close_socket(sfd);

         return -1;

}

 

int close_socket(int sfd)     // 关闭 socket

{

         if (sfd >= 0)

                   close(sfd);

}

 

int main(int argc, char **argv)

{

         int sfd = -1;

         int ret = -1;

         char str[256] = "default";

 

         if (argc > 1)

                   strcpy(str, argv[1]);

 

         sfd = open_socket();

         if (sfd > 0) {

                   ret = write(sfd, str, strlen(str));   // 发送字串

                   printf("send: %s (%d)/n", str, ret);

                   close_socket(sfd);

         } else {

                   perror("socket");

         }

}

u        接收方 recv.c

#include <sys/socket.h>

#include <netinet/in.h>

#include <stdlib.h>

#include <stdio.h>

#include <string.h>

 

#define MSG_PORT 5432

 

int main(int argc, char *argv[])

{

         int sfd, cfd;

         struct sockaddr_in my_addr, peer_addr;

         int peer_addr_size;

         char str[256] = "";

         int ret = -1;

 

         sfd = socket(AF_INET, SOCK_STREAM, 0);       // 建立 TCP 连接

         if (sfd == -1)

         {

                   perror("socket");

                   return -1;

         }

 

         memset(&my_addr, 0, sizeof(struct sockaddr_in));

         my_addr.sin_family = AF_INET;

         my_addr.sin_addr.s_addr = 0;

         my_addr.sin_port = htons(MSG_PORT);

 

         if (bind(sfd, (struct sockaddr *) &my_addr,   // 绑定

                     sizeof(struct sockaddr_in)) == -1)

         {

                   perror("bind");

                   return -1;

         }

 

         if (listen(sfd, 10) == -1)       // 监听

         {

                   perror("listen");

                   return -1;

         }

 

         peer_addr_size = sizeof(struct sockaddr_in);

         cfd = accept(sfd, (struct sockaddr *) &peer_addr, &peer_addr_size);     // 等待连接

         if (cfd == -1)

         {

                   perror("accept");

                   return -1;

         }

         while(ret <= 0)

         {

                   ret = read(cfd, str, 256);      // 读取数据

         }

         printf("recv: %s (%d)/n", str, ret);

         if (ret < 0)

                   perror("recv");

         close(cfd); // 关闭连接

         close(sfd);

}

l          编译

gcc send.c -o send

gcc recv.c -o recv

l          执行结果
在一个终端运行 recv 等待接收数据变化
另一个终端运行 send ,参数是要发送的字串
此时在 recv 终端看到收到发送过来的字串

Ø       参考

l          例程下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/case%7C_socket.tgz

 

例程之七_IPC_system_signal

Ø       功能

l          进程间通讯 (IPC)

Ø       知识点

l          通讯的实现:使用系统底层的信号机制

l          只能传输简单的信号,不能传输数据

l          供用户使用的信号只有 SIGUSR1 SIGUSR2 两个

l          使用方法十分简单

Ø       示例

l          源码

u        发送方 send.c

#include <stdio.h>

#include <signal.h>

 

int main(int argc, char **argv)

{

         FILE *pp = NULL;

         char str[256];

         int pid = 0;

 

         // 获取 recv 程序所对应的进程号

         if ((pp = popen("ps -e|grep recv|awk '{print $1}'", "r")) != NULL) {      

                   if (fgets(str, 25, pp) != NULL) {

                            pid = atoi(str);

                            if (pid > 0) {

                                     printf("now send usr1 signal/n");

                                     kill(pid, SIGUSR1);   // 发送信号

                            }

                   }

                   pclose(pp);

         }

         return 0;

}

u        接收方 recv.c

#include <signal.h>

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

 

static void killfun(int signo)       // 信号回调函数

{

         printf("recv kill signal %d/n", signo);

         exit(1);

}

 

int main(void)

{

         if (signal(SIGUSR1, killfun) == SIG_ERR)          // 注册 usr1 信号的回调函数

                   perror("can't catch SIGUSR1");

 

         while (1) { // 循环等待

                   printf("wait.../n");

                   usleep(500000);

         }

}

l          编译

gcc send.c -o send

gcc recv.c -o recv

l          执行结果
在一个终端运行 recv 等待接收数据变化
另一个终端运行 send
此时在 recv 终端看到收到发送过来的信号

Ø       参考

l          例程下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/case%7C_signal.tgz

 

3月15日
例程之六_IPC_DBUS_signal

Ø       功能

l          进程间通讯 (IPC)

l          signal 方式主要用于非阻塞的数据广播
(注意不要传大量数据,否则会引起消息阻塞)

Ø       知识点

l          通讯的实现: C/S 架构,用户进程为 client 端,后台运行着 dbus-daemon 进程为 server 端,用于侦测信息传输及时通知另一进程

l          基本概念:总线,服务,对象,接口,方法和信号

u        总线 (bus) :系统 (System bus) 、会话 (Session bus)
会话总线:同一次登录后用户的各个进程间通讯

系统总线:不同用户及与系统间通讯

u        服务 (service) :每个总线有一个或多个服务
以点分隔 , 至少两个点以避免重名,没层次关系,反序像 java

u        对象 (object) :每个服务有一个或多个对象
对反斜杠 ’/’ 分隔 , 像路径,只是名没层次关系

u        接口 (interface) :每个服务有一个或多个接口
以点分隔,一般接口和对象名差不多

u        方法 (method) 和信号 (signal)
上面都是对传输规则和传输目的的指定,方法和信号是用户真正输的数据

方法是阻塞的点对点的
信号是非阴阻塞的可广播的 ( 本例程主要介绍信号 )

l          一般程序不直接使用 D-Bus 的接口。 DBus-glib GTK 版本的 dbus 接口封装,下面例程就是使用 DBus-glib 实现的

Ø       示例

l          源码

u        发送程序 send.c

#include <dbus/dbus.h>

#include <glib.h>

#include <string.h>

#include <stdlib.h>

 

#define TEST_OBJECT "/com/test/notifications"

#define TEST_INTERFACE "com.test.notifications"

#define TEST_SIGNAL "set_msg"

 

int main(int argc, char **argv)

{

         DBusConnection *bus;

         DBusError error;

         DBusMessage *message;

         char *p;

 

         p = (char*) malloc (256 * sizeof(char));

         strcpy(p, "default");

         if (argc > 1)

                   strcpy(p, argv[1]);

 

         dbus_error_init(&error);

         bus = dbus_bus_get(DBUS_BUS_SESSION, &error);

         if (!bus) {

                   g_warning("Failed to connect to the D-BUS daemon: %s",

                              error.message);

                   dbus_error_free(&error);

                   return -1;

         }

         dbus_connection_setup_with_g_main(bus, NULL);

         message = dbus_message_new_signal(TEST_OBJECT, TEST_INTERFACE, TEST_SIGNAL);

         dbus_message_append_args(message,

                            DBUS_TYPE_STRING, &p, DBUS_TYPE_INVALID);

         dbus_connection_send(bus, message, NULL);

         dbus_message_unref(message);

 

         free(p);

         return 0;

}

u        接收程序 recv.c

#include <glib.h>

#include <dbus/dbus.h>

#include <stdio.h>

 

#define TEST_OBJECT "/com/test/notifications"

#define TEST_INTERFACE "com.test.notifications"

#define TEST_SIGNAL "set_msg"

 

static DBusHandlerResult

signal_filter(DBusConnection * connection, DBusMessage * message,

               void *user_data)

{

         GMainLoop *loop = user_data;

         if (dbus_message_is_signal(message, TEST_INTERFACE, TEST_SIGNAL))

         {

                   DBusError error;

                   char *s;

                   dbus_error_init(&error);

                   if (dbus_message_get_args

                       (message, &error, DBUS_TYPE_STRING, &s,

                        DBUS_TYPE_INVALID)) {

                            printf("dbus received: %s/n", s);

                   } else {

                            printf

                                ("dbus received, but error getting message: %s/n",

                                 error.message);

                            dbus_error_free(&error);

                   }

                   return DBUS_HANDLER_RESULT_HANDLED;

         }

         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

}

 

int main(int argc, char **argv)

{

         GMainLoop *loop;

         DBusConnection *bus;

         DBusError error;

         char str[256];

 

         loop = g_main_loop_new(NULL, FALSE);

         dbus_error_init(&error);

         bus = dbus_bus_get(DBUS_BUS_SESSION, &error);

         if (!bus) {

                   g_warning("Failed to connect to the D-BUS daemon: %s",

                              error.message);

                   dbus_error_free(&error);

                   return 1;

         }

         dbus_connection_setup_with_g_main(bus, NULL);

         sprintf(str, "type='signal',interface='%s'", TEST_INTERFACE);

         dbus_bus_add_match(bus, str, &error);

         dbus_connection_add_filter(bus, signal_filter, loop, NULL);

         g_main_loop_run(loop);

         return 0;

}

l          编译

gcc send.c -o send `pkg-config --libs --cflags dbus-1 glib-2.0 dbus-glib-1 dbus-1`

gcc recv.c -o recv `pkg-config --libs --cflags dbus-1 glib-2.0 dbus-glib-1 dbus-1`

l          执行结果
在一个终端运行 recv 等待接收数据变化
另一个终端运行 send ,参数是要发送的字串
此时在 recv 终端看到收到发送过来的字串

Ø       参考

l          例程下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/case%7C_dbus%7C_signal.tgz

 

例程之五_IPC_gconf

Ø       功能

l          配置及管理应用程序相关的数据,功能类似注册表

l          进程间通讯 (IPC)

Ø       知识点

l          通讯的实现: C/S 架构,用户进程为 client 端,后台运行着 gconfd-2 进程为 server 端,用于侦测配置文件的变化,及时通知另一进程(另一进程会注册它所关心值的回调函数,值改变时回调函数被调用)

l          存储配置的实现: gconf 是以配置文件方式存储,格式为纯文本的文件( Key/Value ),它存储在 $HOME/.gconf/ 目录下,所以只用于同一用户数据的交互

l          读取配置项时,可按类型直接读取值,也可以先读取数据项是何种类型

l          调试工具 gconf-editor ,使用它可以看到该用户的所有配置项及配置某项

Ø       示例

l          源码

u        发送方 send.c

#include <gconf/gconf-client.h>

#include <string.h>

 

#define TEST_ITEM "/extra/test/txt"                   // 配置关键字(相当于 key 值)

#define TEST_DIR "/extra/test"                            // 配置存放的上层目录,对应 $HOME/.gconf 下的目录结构

 

int main(int argc, char **argv)

{

         GConfClient *client;

         char str[256] = "default";

 

         if (argc > 1)

                   strcpy(str, argv[1]);     // 用程序参数作为设置值

         gconf_init(argc, argv, NULL);      // gconf client 端的初始化

         client = gconf_client_get_default();    // 获得 gconf 句柄

         gconf_client_set_string(client, TEST_ITEM, str, NULL);     // 设置 String 类型的值

         return 0;

}

u        接收方 recv.c

#include <gconf/gconf-client.h>

#include <stdio.h>

 

#define TEST_ITEM "/extra/test/txt"

#define TEST_DIR "/extra/test"

 

void key_changed_callback(GConfClient * client,       // 配置值改变时被回调的函数

                              guint cnxn_id,

                              GConfEntry * entry, gpointer user_data)

{

         gchar *str;

         str = gconf_client_get_string(client, TEST_ITEM, NULL);  // 获得 String 型的设置值

         if (str) {

                   printf("recv: %s/n", str);

                   g_free(str);

         }

}

 

int main(int argc, char **argv)

{

         GConfClient *client;

         static GMainLoop *main_loop = NULL;

 

         gconf_init(argc, argv, NULL);

         client = gconf_client_get_default();

 

         gconf_client_add_dir(client,       // 设置上层目录,以备侦测配置值的变化

                                 TEST_DIR, GCONF_CLIENT_PRELOAD_NONE, NULL);

         gconf_client_notify_add(client, TEST_ITEM,      // 注册回调函数

                                     (GConfClientNotifyFunc)

                                     key_changed_callback, NULL, NULL, NULL);

 

         main_loop = g_main_loop_new(NULL, FALSE);  // gconf 需要依赖 glib 的主循环

         g_main_loop_run(main_loop);

         g_main_loop_unref(main_loop);

 

         return 0;

}

l          编译

gcc -o send send.c `pkg-config --cflags --libs gconf-2.0`

gcc -o recv recv.c `pkg-config --cflags --libs gconf-2.0`

l          执行结果
在一个终端运行 recv 等待接收数据变化
另一个终端运行 send ,参数是要发送的字串
此时在 recv 终端看到收到发送过来的字串

Ø       参考

l          例程下载
http://cid-f8aecd2a067a6b17.skydrive.live.com/self.aspx/.Public/case%7C_gconf.tgz

 

3月7日
例程之四_GUI_GTK三维效果的实现

Ø       功能

l          使用 clutter Gtk 窗口中实现三维效果,通常用于过渡效果和三维界面

Ø       知识点

l          clutter 原理
clutter
底层调用 opengl glx 等库,实现三维效果,而向上层提供了统一简单 ( opengl 简单很多 ) 的接口,支持常用的 GUI(gtk/qt )

l          clutter stage( 舞台 ) actor( 演员 ) 的概念
每个 gtk window 可以包含一个或多个 stage ,每个 stage 有它的大小,颜色等属性
一个 stage 里又包含一个或多个 actor actor 来实现具体动画

l          总在顶层显示
clutter
所在的窗口应该是最顶层的,因为在动画过程中, clutter 产生的画面将盖在其它任何窗口之上

Ø       示例

l          环境
ubuntu 8.04 系统,安装 clutter-0.8.0.tar.bz2 clutter-gtk-0.8.0.tar.gz
(尽量安装源码包,因为其中包括一些例程,可以参考)

l          源码

#include <gtk/gtk.h>

#include <clutter/clutter.h>

#include <clutter-gtk/gtk-clutter-embed.h>

#include <clutter-gtk/gtk-clutter-util.h>

 

static gboolean rotate_timeout(ClutterActor * image)                  // 动画的实现函数,被定时器回调

{

        static int rotate = 0;   // 角度

        rotate += 5;

        if (rotate > 360)

                 rotate = 0;

        clutter_actor_set_rotation(image, CLUTTER_X_AXIS, rotate, 0, 0, 0); // 绕X轴旋转,后三个参数分别是旋转轴心的 x, y, z

        return TRUE;

}

 

int main(int argc, char *argv[])

{

        ClutterActor *stage1, *tex1, *tex2;

        GtkWidget *window, *clutter;

        GdkPixbuf *pixbuf;

 

        if (gtk_clutter_init(&argc, &argv) != CLUTTER_INIT_SUCCESS)      // 初始化 clutter

                 g_error("Unable to initialize GtkClutter");

 

        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

        g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit),

                             NULL);

 

        clutter = gtk_clutter_embed_new();    // 建立 clutter 实例

        gtk_widget_set_size_request(clutter, 320, 240);   // 设定 clutter 大小

        stage1 = gtk_clutter_embed_get_stage(GTK_CLUTTER_EMBED(clutter)); // stage

 

        tex1 = clutter_texture_new_from_file("bg.jpg", NULL);      // 读取背景图片,此函数在 clutter-0.8.0 以上版本中使用的, 0.6.0 此功能使用函数 clutter_texture_new_from_pixbuf

        clutter_actor_set_position(tex1, 0, 0); // 设置 actor 相对于 stage 位置

        clutter_stage_add(stage1, tex1);

        clutter_actor_show(tex1);

 

        tex2 = clutter_texture_new_from_file("img.jpg", NULL);   // 读取被旋转的图片

        clutter_actor_set_position(tex2,

                                       (320 - clutter_actor_get_width(tex2)) / 2, 120);        // 设置图片旋转位置

        clutter_group_add(CLUTTER_GROUP(stage1), tex2);

 

        gtk_container_add(GTK_CONTAINER(window), clutter);    // clutter 加入 gtk window

        gtk_widget_show_all(window);

        clutter_actor_show_all(stage1);

 

        g_timeout_add(150, (GSourceFunc) rotate_timeout, tex2);  // 加入定时器,以旋转

        gtk_main();

 

        return 0;

}

l          编译
g++ main.cpp -o main ` pkg-config gtk+-2.0 clutter-gtk-0.8 --libs --cflags`

l          执行结果
后面显示背景图,前面的画面绕X轴旋转

 

Ø       参考

l          clutter 介绍
http://jserv.sayya.org/clutter/clutter-overview.pdf

l          完整例程下载(含图片及 Makefile
http://cid-f8aecd2a067a6b17.skydrive.live.com/browse.aspx/.Public?uc=1&isFromRichUpload=1

下载 case_gtkclutter.tgz

3月6日
例程之三_GUI_无边框GTK窗口的拖拽

Ø       功能

l          无标题栏 ( 无边框 )GTK 窗口的拖拽

Ø       知识点

l          窗口内部接收和处理鼠标拖动事件,同时移动窗口位置

Ø       示例

l          源码

#include <gdk/gdkcursor.h>

#include <gtk/gtk.h>

 

#define TEST_W 100

#define TEST_H 80

 

gboolean drag = FALSE;   // 只在左键按下时拖动窗体

int nX = 0;

int nY = 0;

 

static gint button_press_event(GtkWidget * widget,

          GdkEventButton * event, gpointer data)

{

        if (event->button == 1)       // 判断是否左键按下

        {

                 drag = TRUE;

                 nX = event->x;  // 取得鼠标相对于窗口的位置

                 nY = event->y;

        }

        return TRUE;

}

 

static gint button_release_event(GtkWidget * widget, GdkEventButton * event,

          gpointer data)         // 鼠标抬起事件

{

        if (event->button == 1)

                 drag = FALSE;

        return TRUE;

}

 

static gint motion_notify_event(GtkWidget * widget, GdkEventButton * event,

          gpointer data)         // 鼠标移动事件

{

        if (drag)

        {

                 int x, y;

                 GtkWidget *window = (GtkWidget *) data;

                 gtk_window_get_position((GtkWindow *) window, &x, &y);         // 取窗体绝对坐标

                 gtk_window_move((GtkWindow *) window, x + event->x - nX,

                             y + event->y - nY); // 移动窗体

        }

        return TRUE;

}

 

int main(int argc, char **argv)

{

        GtkWidget *window;

 

        gtk_init(&argc, &argv);

 

        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

        gtk_window_set_decorated(GTK_WINDOW(window), FALSE);    // 去掉边框

        gtk_widget_set_size_request(window, TEST_W, TEST_H);

 

        gtk_widget_set_events(window,  // 设置窗体获取鼠标事件

                   GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK

                   | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK

                   | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK);

        gtk_signal_connect(GTK_OBJECT(window), "button_press_event",

                   (GtkSignalFunc) button_press_event, window);       // 加入 事件回调

        gtk_signal_connect(GTK_OBJECT(window), "motion_notify_event",

                   (GtkSignalFunc) motion_notify_event, window);

        gtk_signal_connect(GTK_OBJECT(window), "button_release_event",

                   (GtkSignalFunc) button_release_event, window);

 

        gtk_widget_show_all(window);

        gtk_main();

        return TRUE;

}

l          编译
gcc main.cpp –o main `pkg-config gtk+-2.0 –libs –cflags`

l          执行结果
显示窗口,按下鼠标左键时可以拖动

 

2月21日
例程之二_Debug_显示当前函数调用关系

Ø       功能

l          程序异常退出时,显示当时的函数调用关系

l          显示当前函数正在被哪个函数调用

Ø       知识点

l          backtrace 函数显示当前进程堆栈信息(当时函数调用关系)

Ø       示例

l          源码

#include <stdio.h>

 

void xy_print_backtrace(void)

{

        void *bt[500];

        int i = 0;

        int bt_size;

        char **syms;

 

        bt_size = backtrace(bt, 500);       // 获取当前堆栈信息,最多 500 层函数

        syms = (char**)backtrace_symbols(bt, bt_size);  // 把堆栈信息转化成字符串数组

 

        while (i < bt_size)

        {

                 printf("%s/n", syms[i]);

                 ++i;

        }

        free(syms);

}

 

void xy_level2()

{

        xy_print_backtrace();

}

 

void xy_level1()

{

        xy_level2();

}

 

int main(int argc, char **argv)

{

        xy_level1();

}

l          编译
gcc main.c -o main –rdynamic
// 注意加编译参数-rdynamic ,才能正常使用backtrace

l          执行结果
./main(xy_print_backtrace+0x26) [0x80486ba]
./main(xy_level2+0xb) [0x804870e]
./main(xy_level1+0xb) [0x804871b]
./main(main+0x16) [0x8048733]
/lib/tls/i386/cmov/libc.so.6(__libc_start_main+0xe0) [0xb7dcf450]
./main [0x8048631]

例程之一_Debug_规范化打印信息

Ø       功能

l          规范化程序打印信息

l          打印当前运行程序所对应的源码位置

l          统计程序运行时间

Ø       知识点

l          接收可变参数 (va_start, vfprintf, va_end)

l          打印当前位置的源码文件名及行数

l          获取当前时间 ( 微秒 )

Ø       示例

l          源码

#include <stdio.h>

#include <stdarg.h>

#include <time.h>

#include <sys/time.h>

 

#define _DEBUG      // 方便显示或隐藏打印信息

 

void xy_debug(const char *format, ...)         // 接收可变参数

{

#ifdef _DEBUG

        va_list args;

        time_t timep;

        struct tm *p;

        struct timeval tv;

 

        if (format == NULL)

                 return;

 

        time(&timep);   // 取当前时间(年月日时分秒)

        p = localtime(&timep);       // 获取对应本地时区的时间

        gettimeofday(&tv, NULL);  // 获取微秒时间

 

        fprintf(stderr, "[%d:%d:%d.%06d] ", p->tm_hour, p->tm_min, p->tm_sec,

                   tv.tv_usec);     // 分别使用两个函数获取时间,省略除法计算,节约运行时间

        va_start(args, format);        // 接收可变参数

        vfprintf(stderr, format, args);

        va_end(args);

 

        fflush(stderr);   // 同步缓冲区,使程序立即显示

#endif

}

 

main()

{

        xy_debug("(%s:%d) test_%d/n", __FILE__, __LINE__, 100);        // 用法如同 printf
        // __FILE__
当前文件名的宏定义, __LINE__ 当前行数的宏定义

}

l          编译
gcc main.c -o main

l          执行结果
[22 3 56.100282] main.c:35 test_100

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值