ubox是Openwrt的一个帮助工具包, 包含了MD5,链表,平衡树,blob标签式二进制数据包的生成和解释......等等基础API, 以及uloop,usock,ustream,ulog等应用。 通过学习ubox可以更好地理解和融入Openwrt框架体系。
通过应用其中的uloop和usock可实现基于文件句柄监控和事件驱动机制的C/S结构网络通信应用。 以下是一个实现的小例子:
1. 服务端 usock_server.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> #include <libubox/usock.h> #include <libubox/uloop.h> static char *host_addr="192.168.1.9"; static char *server_port="5678"; static char *strhello="Welcome to UBOX world!\n"; static char *strreply="Add client to uloop_fd_event successfully!\n"; /* client fd event call_back */ void sevent_cb(struct uloop_fd *fd, unsigned int events) { char buf[1024]; struct timeval tm; int ret; gettimeofday(&tm,NULL); if(events & ULOOP_READ) { printf("%ld: ULOOP_READ is triggered! sock fd=%d, events=%d\n", tm.tv_sec,fd->fd, events); ret=read(fd->fd, buf, sizeof(buf)); buf[ret]=0; printf("Client MSG: %s \n", buf); if(events & ULOOP_WRITE) { write(fd->fd, strhello, strlen(strhello)); } } } /* server fd event call_back function */ void server_cb(struct uloop_fd *fd, unsigned int events) { printf("server_cb is triggered! events=%d\n",events); int client_fd=accept(fd->fd, NULL,0); if(client_fd<0) { perror("server_cb accept"); return; } printf(" >>>>>>> New client accepted! >>>>>>\n"); write(client_fd,strhello,strlen(strhello)); struct uloop_fd *ucli_fd=calloc(1,sizeof(struct uloop_fd)); if(ucli_fd==NULL) return; /* add client fd to uloop event */ ucli_fd->fd= client_fd; ucli_fd->cb = sevent_cb; printf("Add client to uloop_fd...\n"); uloop_fd_add(ucli_fd, ULOOP_READ | ULOOP_WRITE | ULOOP_EDGE_TRIGGER); } struct uloop_fd server_fd = { .cb = server_cb, }; void main(void) { int sfd; char buf[1024]; /* 1. init uloop */ uloop_init(); /* 2. create server usock */ sfd=usock(USOCK_TCP|USOCK_SERVER, host_addr, server_port); if(sfd<0) { perror("usock"); exit(-1); } printf("Succeed to create server at %s:%s\n",host_addr, server_port); /* 3. add server fd to uloop event */ server_fd.fd=sfd; uloop_fd_add(&server_fd, ULOOP_READ | ULOOP_EDGE_TRIGGER); /* read only */ /* 4. loop events monitoring */ uloop_run(); /* 5. end uloop */ uloop_done(); }2. 客户端 usock_client.c
#include <stdio.h> #include <stdlib.h> #include <libubox/usock.h> #include <libubox/uloop.h> #include <string.h> #include <sys/time.h> char *host_addr="192.168.1.9"; char *server_port="5678"; char *strhello="Hello UBOX!"; void cevent_cb(struct uloop_fd *fd, unsigned int events) { char buf[1024]; struct timeval tm; gettimeofday(&tm,NULL); if(events & ULOOP_READ) { printf("%ld: event ULOOP_READ is triggered! sock fd=%d, events=%d\n",tm.tv_sec, fd->fd, events); read(fd->fd, buf, sizeof(buf)); printf("MSG from server: %s \n", buf); if(events & ULOOP_WRITE) { write(fd->fd, strhello, strlen(strhello)); } sleep(1); } } struct uloop_fd client_fd = { .cb = cevent_cb, }; void main(void) { int cfd; char buf[1024]; int ret; uloop_init(); cfd=usock(USOCK_TCP, host_addr, server_port); if(cfd<0) { perror("usock"); exit(-1); } printf("Connect to server %s:%s successfuly!\n", host_addr, server_port); ret=read(cfd, buf, sizeof(buf)); buf[ret]=0; printf("receive msg: %s\n",buf); /* send a msg to trigger ping_pong events */ write(cfd, strhello, strlen(strhello)); client_fd.fd=cfd; uloop_fd_add(&client_fd, ULOOP_READ | ULOOP_WRITE ); printf("start uloop_run() ...\n"); uloop_run(); uloop_done(); }3. 本例子在openwrt widora环境下编译通过, Makefile 如下:
export STAGING_DIR=/home/midas-zhou/openwrt_widora/staging_dir COMMON_USRDIR=/home/midas-zhou/openwrt_widora/staging_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/usr/ CC= $(STAGING_DIR)/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mipsel-openwrt-linux-gcc CFLAGS += -I$(COMMON_USRDIR)/include LDFLAGS += -L$(COMMON_USRDIR)/lib LIBS += -lubox all: usock_server usock_client test_timeout usock_server: usock_server.c $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) usock_server.c -o usock_server usock_client: usock_client.c $(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) usock_client.c -o usock_client clean: rm -rf *.o usock_server usock_client4. 在openwrt中试验, 首先运行usock_server, 然后启动若干个usock_client, 观察实际效果。
5. 备注: 程序中host_addr 和 Makefile环境变量请根据自己实际情况修改。