|
声明:作者同意将本文自由传播,但不得删改包括本声明及以下呼吁在内的任何内容。
呼吁:宪法第一条“中华人民共和国是工人阶级领导的、以工农联盟为基础的、
人民民主专政的社会主义国家。”所体现的阶级等级和专政思想与“人权天赋、
约法共和、自主选择、平等竞争”的政治文明常识相违背,呼吁人大将其改为
“中国是全体公民组成的,致力于保障公民基本权利,为公民的生存与发展提供
良好公共环境的法治国家。中国全体公民的基本权利一律平等。”
判断程序是否阻塞的小工具alive
丁建华 <[email protected]> 2004.8.16
glib 的网络编程主要有两种模式: "单线程非阻塞" 和 "多线程阻塞". 这一点
在 gnet 项目上有非常明显的体现. 按说还有一种"多线程非阻塞"模式, 但是由于
glib 的 API 有许多是对缺省主循环上下文 (default main context) 进行操作的,
而这个上下文在目前的 2.4.2 版还没有被改成"每个线程一个"的形式, (这一改动
牵扯面太广, 而且似乎动力不足, 用户需求不强烈.) 所以没人采用"多线程非阻塞"
模式. 阻塞模式也受限制, 比如双向随机的数据传输, 用阻塞模式就需要两个线程.
因此目前用的最多的, 还是"单线程非阻塞"模式.
可是初学者常常把握不住非阻塞, 一不小心就把程序阻塞了. 为此我专门做了
一个小程序 alive, 在指定端口上侦听. 用 telnet 连接到该端口, 就可以不断地
收到点点点. 如果你的程序不幸被阻塞了, 自然就没有点点点了. )
程序在 Cygwin 下编译通过. 有关 Cygwin/GTK+ 配置问题请到
一塌糊涂(ytht.net)个人文集区找 dingjh 个人文集.
本人水平有限, 欢迎批评指正.
<file "Makefile">
all: alive.exe
SUFFIXES:
SUFFIXES: .exe .o .c
alive.exe : main.o alive.o revscon.o
gcc -mno-cygwin -o $@ $^ `pkg-config --libs glib-2.0` -lwsock32
c.o:
gcc -c -Wall -O2 -mno-cygwin -mms-bitfields -o $@ $< \
`pkg-config --cflags glib-2.0`
clean:
@rm -f *.exe *.o
PHONY: all
</file>
<file "main.c">
#include <glib.h>
#include "alive.h"
#include "revscon.h"
#include "os_stuff.h"
int main(int argc, char *argv[])
{
GMainLoop * mloop;
revs_con * con;
alive_lsnr * lsnr;
#ifdef G_OS_WIN32
{
WSADATA wsa;
gint err;
if (0 != (err = WSAStartup(MAKEWORD(2, 2), &wsa)))
g_error("Winsock 2.2 does not be supported (%d)", err);
if (2 != LOBYTE(wsa.wVersion) || 2 != HIBYTE(wsa.wVersion))
g_error("Can't found suitable winsock dll");
}
#endif
mloop = g_main_loop_new(NULL, FALSE);
con = revs_con_new(mloop);
lsnr = alive_lsnr_new("10.0.1.1", 6767); /* IP, PORT 任意*/
g_main_loop_run(mloop);
alive_lsnr_unref(lsnr);
revs_con_unref(con);
g_main_loop_unref(mloop);
#ifdef G_OS_WIN32
WSACleanup();
#endif
return 0;
}
</file>
<file "alive.h">
#ifndef _alive_h_
#define _alive_h_
#include <glib.h>
typedef struct _alive_lsnr alive_lsnr;
alive_lsnr * alive_lsnr_new(gchar *a_addr, gshort port);
void alive_lsnr_ref(alive_lsnr * lsnr);
void alive_lsnr_unref(alive_lsnr * lsnr);
#endif
</file>
<file "revscon.h">
#ifndef _revscon_h_
#define _revscon_h_
#include <glib.h>
typedef struct _revs_con revs_con;
revs_con * revs_con_new(GMainLoop * mloop);
void revs_con_ref(revs_con * con);
void revs_con_unref(revs_con * con);
#endif
</file>
<file "os_stuff.h">
#ifndef _os_stuff_h_
#define _os_stuff_h_
#ifdef G_OS_WIN32
#include <windows.h>
#include <winsock.h>
#endif
#ifdef G_OS_UNIX
/* #include <...> FIXME: 尚未完成!!! */
#define WSAGetLastError errorno
#define closesocket close
#endif
#endif
</file>
<file "alive.c">
#include <glib.h>
#include "alive.h"
#include "os_stuff.h"
struct _alive_lsnr {
gint ref_count;
GIOChannel * channel;
GSList * connections;
};
typedef struct _alive_conn {
gint ref_count;
gint column;
GIOChannel * channel;
alive_lsnr * listener;
} alive_conn;
static gboolean alive_lsnr_func(GIOChannel *source, GIOCondition condition,
gpointer data);
alive_conn * alive_conn_new(gint sock, alive_lsnr *lsnr)
{
gint written;
alive_conn * conn = g_new0(alive_conn, 1);
conn->ref_count = 1;
conn->column = 0;
conn->channel = g_io_channel_unix_new(sock);
g_io_channel_set_encoding(conn->channel, NULL, NULL);
g_io_channel_set_buffered(conn->channel, FALSE);
conn->listener = lsnr;
lsnr->connections = g_slist_prepend(lsnr->connections, conn);
g_io_channel_write_chars(conn->channel, "Hello, alive-client!\n\n",
-1, &written, NULL);
return conn;
}
void alive_conn_ref(alive_conn * conn)
{
g_return_if_fail(NULL != conn);
g_return_if_fail(g_atomic_int_get(&conn->ref_count) > 0);
g_atomic_int_inc(&conn->ref_count);
}
void alive_conn_unref(alive_conn * conn)
{
gint sock, written;
alive_lsnr * lsnr = conn->listener;
g_return_if_fail(NULL != conn);
g_return_if_fail(g_atomic_int_get(&conn->ref_count) > 0);
if (!g_atomic_int_dec_and_test(&conn->ref_count))
return;
g_io_channel_write_chars(conn->channel, "\n\nGoodbye, alive-client!",
-1, &written, NULL);
sock = g_io_channel_unix_get_fd(conn->channel);
g_io_channel_shutdown(conn->channel, TRUE, NULL);
g_io_channel_unref(conn->channel);
g_io_channel_unref(conn->channel);
closesocket(sock);
lsnr->connections = g_slist_remove(lsnr->connections, conn);
g_free(conn);
}
gboolean alive_timeout_func(gpointer data)
{
gint written;
alive_conn * conn = (alive_conn *)data;
if (G_IO_STATUS_NORMAL == g_io_channel_write_chars(
conn->channel, ".", -1, &written, NULL)) {
if (++ conn->column >= 60) {
g_io_channel_write_chars(conn->channel, "\n", -1,
&written, NULL);
conn->column = 0;
}
return TRUE;
}
alive_conn_unref(conn);
return FALSE;
}
gboolean alive_conn_func(GIOChannel *source, GIOCondition condition,
gpointer data)
{
if (condition & G_IO_IN) {
gchar buff[256];
gsize read, written;
GError * error = NULL;
g_io_channel_read_chars(source, buff, sizeof(buff),
&read, &error);
if (NULL == error && read > 0) {
g_io_channel_write_chars(source, buff, read,
&written, &error);
if (NULL == error) {
return TRUE; // read, write OK!
}
}
}
// something wrong, or closed by peer
alive_conn_unref((alive_conn *) data);
return FALSE;
}
alive_lsnr * alive_lsnr_new(gchar *a_addr, gshort port)
{
alive_lsnr * lsnr = g_new0(alive_lsnr, 1);
struct sockaddr_in addr;
gint sock;
if (INVALID_SOCKET == (sock = socket(PF_INET, SOCK_STREAM, 0)))
g_error("socket: %d\n", WSAGetLastError());
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(a_addr);
if (SOCKET_ERROR == bind(sock, (struct sockaddr *)&addr, sizeof(addr)))
g_error("bind: %d\n", WSAGetLastError());
if (SOCKET_ERROR == listen(sock, 5))
g_error("listen: %d\n", WSAGetLastError());
lsnr->channel = g_io_channel_unix_new(sock);
lsnr->connections = NULL;
lsnr->ref_count = 1;
g_io_add_watch(lsnr->channel, G_IO_IN | G_IO_ERR | G_IO_HUP,
&alive_lsnr_func, lsnr);
return lsnr;
}
void alive_lsnr_ref(alive_lsnr * lsnr)
{
g_return_if_fail(NULL != lsnr);
g_return_if_fail(g_atomic_int_get(&lsnr->ref_count) > 0);
g_atomic_int_inc(&lsnr->ref_count);
}
void alive_lsnr_unref(alive_lsnr * lsnr)
{
gint sock;
g_return_if_fail(NULL != lsnr);
g_return_if_fail(g_atomic_int_get(&lsnr->ref_count) > 0);
if (!g_atomic_int_dec_and_test(&lsnr->ref_count))
return;
sock = g_io_channel_unix_get_fd(lsnr->channel);
g_io_channel_unref(lsnr->channel);
g_io_channel_unref(lsnr->channel);
closesocket(sock);
while (NULL != lsnr->connections) {
alive_conn * conn;
conn = (alive_conn *) lsnr->connections->data;
alive_conn_unref(conn);
alive_conn_unref(conn);
}
g_free(lsnr);
}
gboolean alive_lsnr_func(GIOChannel *source, GIOCondition condition,
gpointer data)
{
struct sockaddr addr;
gint len = sizeof(addr);
gint sock, s;
alive_conn * conn;
g_return_val_if_fail(condition & G_IO_IN, FALSE);
sock = g_io_channel_unix_get_fd(source);
if (INVALID_SOCKET == (s = accept(sock, &addr, &len))) {
g_printerr("accept: %d\n", WSAGetLastError());
return FALSE;
}
conn = alive_conn_new(s, (alive_lsnr *)data);
g_timeout_add(500, &alive_timeout_func, conn);
g_io_add_watch(conn->channel, G_IO_IN | G_IO_ERR | G_IO_HUP,
&alive_conn_func, conn);
alive_conn_ref(conn); // _new and ref_ for _timeout and watch_
return TRUE;
}
</file>
<file "revscon.c">
#include <stdio.h>
#include <glib.h>
#include "revscon.h"
#include "os_stuff.h"
struct _revs_con {
gint ref_count;
GIOChannel * in;
GIOChannel * out;
GMainLoop * mloop;
};
static gboolean revs_con_func(GIOChannel *source, GIOCondition condition,
gpointer data);
revs_con * revs_con_new(GMainLoop * mloop)
{
gint written;
revs_con * con = g_new0(revs_con, 1);
con->ref_count = 1;
con->in = g_io_channel_unix_new(fileno(stdin));
g_io_channel_set_encoding(con->in, NULL, NULL);
if (!con->in->is_readable) /* For Win32 !!! */
con->in->is_readable = TRUE;
con->out = g_io_channel_unix_new(fileno(stdout));
g_io_channel_set_encoding(con->out, NULL, NULL);
g_io_channel_write_chars(con->out, "Hello, I'm reverse-console!\n"
"Type 'quit' to quit.\n\n", -1,
&written, NULL);
g_io_channel_flush(con->out, NULL);
con->mloop = mloop;
g_io_add_watch(con->in, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
&revs_con_func, con);
return con;
}
void revs_con_ref(revs_con * con)
{
g_return_if_fail(NULL != con);
g_return_if_fail(g_atomic_int_get(&con->ref_count) > 0);
g_atomic_int_inc(&con->ref_count);
}
void revs_con_unref(revs_con * con)
{
g_return_if_fail(NULL != con);
g_return_if_fail(g_atomic_int_get(&con->ref_count) > 0);
if (!g_atomic_int_dec_and_test(&con->ref_count))
return;
g_io_channel_unref(con->in);
g_io_channel_unref(con->out);
g_free(con);
}
gboolean revs_con_func(GIOChannel *source, GIOCondition condition,
gpointer data)
{
gchar * line, ch;
gint len, crpos, written;
revs_con * con = (revs_con *)data;
g_return_val_if_fail(condition & G_IO_IN,
(g_main_loop_quit(con->mloop), FALSE));
if (G_IO_STATUS_NORMAL == g_io_channel_read_line(
source, &line, &len, &crpos, NULL)) {
ch = line[crpos];
line[crpos] = '\0';
if (0 == g_ascii_strcasecmp(line, "quit")) {
g_free(line);
return (g_main_loop_quit(con->mloop), FALSE);
}
g_strreverse(line);
line[crpos] = ch;
g_io_channel_write_chars(con->out, line, -1, &written, NULL);
g_io_channel_flush(con->out, NULL);
g_free(line);
}
return TRUE;
}
</file>
<the-end/>
$Id: alive.bbs,v 1.1.1.1 2004/08/15 14:27:38 djh Exp $
--
支持公民自主,反对为民作主,更反对代民作主。
支持公民平等,反对城市特权,更反对党派特权。
支持守法治国,反对以法治国,更反对以德治国。
支持法权独立,反对行政干预,更反对军权干预。
呼吁人大废除宪法第一条部分人高于其他人的歧视条款,尽快建立独立于行政的
司法体系,实现人人平等、依法共和的现代公民社会。 请一起采用本签名档。
[m[1;33m※ 来源:·饮水思源 bbs.sjtu.edu.cn·[FROM: 61.52.247.254][m |
|