apache-replace-module 代码在https://github.com/zhwj184/apache-replace-module,示例都是从网上找的修改验证过的。apache版本2.4.4
=====================
apache module develop demo,apache 模块开发
对输出结果进行正则替换模块, apache response content replace module,比如域名切换对所有输出url进行替换
apache安装完成之后,使用下面这个命令编译各个模块为so文件
/usr/local/apache/bin/apxs -c helloworld.c
/usr/local/apache/bin/apxs -c urlreplace.c
/usr/local/apache/bin/apxs -c urlreplacefilter.c
/usr/local/apache/bin/apxs -c line-editor.c
编译完之后会在当前目录的.libs下面生存.so的文件,正是apache的so文件。
helloworld.c 是演示输出一段字符串helloworld的content handler,
urlreplace.c 是演示读取http.conf配置之后输出的content handler,
urlreplacefilter.c 是演示读取http.conf配置并将输出小写转为大写的输出过滤器,apache自带的demo做的修改。
line-editor.c 是对输出内容进行正则替换等内容替换的输出过滤器,已经开源的东西,可以实现我们的功能,对输出页面的url域名进行正则替换,项目url为:http://apache.webthing.com/mod_line_edit/。
使用方式如下:在http.conf加入如下配置
#helloworld.c 对应的配置
LoadModule helloworld_module mylib/helloworld.so
<Location /helloworld>
setHandler helloworld
</Location>
#urlreplace.c的配置
srcpath *.china.aaa.com
descpath *.bbb.com
LoadModule pathreplace_module mylib/urlreplace.so
<Location /pathreplace>
setHandler pathreplace
</Location>
#urlreplacefilter.c的配置
LoadModule urlReplace_filter_module mylib/urlreplacefilter.so
定义了一种一对多的依赖的关系,让多个观察者看对象,同时监听某一个主体对象。这个主题对象在状态发生变化时,会通知所有的观察者对象,使它们能够自动更新。
优点:观察者模式所做的工作其实就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不会影响到另外一边的变化.
当一个对象的改变需要同时改变其他对象时,而且它不知道具体有多少对象有待改变时,应该考虑使用观察者模式.
故事情节描述:同事小猪和同事小马趁老板出差的时候,正在查看股市行情,并告诉前台的童子喆“如果老板回来的话,记得通知我们呀!”恰巧,老板忘记带东西,于是推门而入,前台通知同事“老板回来了,关闭股市行情,继续工作!”
//通知者接口
interface Subject
{
void Attach(Observer observer);
void Detch(Observer observer);
void Notify();
String SubjectState
{
get;
set;
}
}
//具体的通知者类可能是前台,也可能是老板
//它们也许有自己的实现方法,但是对于通知者而言,它们都是一样的,所以他们都去实现这个接口。
class Boss:Subject
{
//同事列表
private IList <Observer> observers=new List <Observer>();
private string action;
//增加
public void Attach(Observer observer)
{
observers.Add(observer );
}
//减少
public void Detach(Observer observer)
{
observers.Remove(observer );
}
//通知
public void Notify()
{
foreach(Observer o in observers )
o.Update();
}
//老板状态
public string SubjectState
{
get {return action ;}
set {action=value; }
}
//前台秘书类和老板类类似
class Secretary : Subject
{
//同事列表
private IList <Observer >observers=new List <Observer >();
private string action;
//增加
public void Attach(Observer observer)
{
observers.Add(observer );
}
//减少
public void Detach(Observer observer)
{
observers.Remove(observer );
}
//通知
public void Notify()
{
foreach(Observer o in observers )
o.Update();
}
//老板状态
public string SubjectState
{
get { return action ;}
set { action=value; }
}
}
//抽象观察者
abstract class Observer
{
protected string name;
protected Subject sub;
//抽象通知者类
public Observer(string name, Subject sub)
{
this.name = name;
this.sub = sub;
}
public abstract void Update();
}
//看股票的同事
class StockObserver:Observer
{
//抽象通知者
public StockObserver(string name, Subject sub)
: base(name, sub)
{ }
//抽象通知者状态
public override void Update()
{
Console.WriteLine("{0}{1}关闭股票行情,继续工作!",sub.SubjectState,name);
}
}
//客户端代码
//老板胡汉三
Boss huhansan = new Boss();
//看股票的同事
StockObserver tongshi1 = new StockObserver("小猪",huhansan );
//看股票的同事
StockObserver tongshi2 = new StockObserver("小马",huhansan );
huhansan.Attach(tongshi1);
huhansan.Attach(tongshi2 );
//小马其实是没有被老板通知到的, 所以减去
huhansan.Detach(tongshi2 );
//老板回来
huhansan.SubjectState = "我胡汉三回来了!";
//发出通知
huhansan.Notify();
运行环境:Linux2.6以上
文件说明:tcputil.c --------------- TCP多线程服务框架实现
tcputil.h --------------- 公开函数声明
使用说明:
发送消息必须采用固定的(消息大小,消息体)这种流边界方式,其中消息大小是uint32_t类型,并且是网络字节序。
直接调用start(监听IP, 监听端口,自定义消息处理函数)即可;主要是提供自定义的消息处理函数,原型为:
int msg_handler(int socket, void* buf, uint32_t n),其中: socket-接收消息的socket,buf-消息体内存,n-消息体长度。
几个关键点:
(1)发送和接收n个字节的方法,在readn()和writen()函数实现;
(2)向派生线程传递参数时,注意并发导致的同步问题,参见start()函数中的传参实现;
(3)遵循“malloc和free要成对存在于同一个函数中”,但是(2)违反了这个原则,是否有更好的解决方案?
(4)采用了回调函数机制(类似C#中的事件)来让库使用着自定义消息处理函数;(这也是为了遵循(3)采取的策略);
(5)TCP流边界,采取了(消息大小,消息体)的方式,其中消息大小为4字节无符号整数。
存在问题:
(1)性能问题,目前是直接分配与消息体大小同样的内存来接收消息体;
(2)大消息问题,目前消息不能大于int32_t的最大值;
源码:tcputil.h
#ifndef TCPUTIL_H #define TCPUTIL_H #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/types.h> ssize_t writen(int fd, void* buf, size_t n); ssize_t recvn(int fd, void* buf, size_t n); /*callback function called after received one message, 0-success, -1-error*/ typedef int (*message_handler)(int socket, void * buf, uint32_t size); int start(uint32_t listenip, uint16_t listenport, message_handler handler); #endif
源码:tcputil.c
/**************************************************
*
* $description: collection of functions
* $author: smstong
* $date: Tue Apr 16 10:24:22 CST 2013
*
* ************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
/**************************************************
* func: receive n bytes from socket except an error
* params: fd - socket handle
* buf - memory space to write
* n - size of buf
* return: -1 - error;
* >=0 - actually retceived bytes
*************************************************/
ssize_t recvn(int fd, void* buf, size_t n)
{
char* ptr = (char*)buf; // position pointer
size_t left = n; // bytes left to read
while(left > 0) {
size_t nread = read(fd, ptr, left);
if(nread<0) {
if(errno==EINTR) { // an error occured
nread = 0;
} else {
return -1;
}
} else if(nread==0) { //normally disconnect, FIN segment received
break;
} else {
left -= nread;
ptr += nread;
}
}
return (n-left);
}
/********************************************************
* function: write n bytes to socket except error
* params: fd - socket hanle
* buf - src memory
* n - bytes to write
* return: -1 - error
* >=0 - bytes actually written
* ******************************************************/
ssize_t writen(int fd, void* buf, size_t n)
{
char* ptr = (char*)buf;
size_t left = n;
while(left > 0) {
size_t nwrite = write(fd, ptr,left);
if(nwrite<0) {
if(errno==EINTR) {
nwrite = 0;
} else {
return -1;
}
} else if(nwrite==0) {
break;
} else {
left -= nwrite;
ptr += nwrite;
}
}
return (n-left);
}
static void * thread_f(void *); //thread function
typedef int (*message_handler)(int, void *, uint32_t); // callback function called after received one message
/*************************************************************
*
* one thread per connection frameset
*
* ***********************************************************/
// thread function's args
struct thread_arg {
int socket;
message_handler msg_handler;
};
int start(uint32_t listenip, uint16_t listenport, message_handler handler)
{
int listenfd, connfd;
struct sockaddr_in servaddr;
char buff[4096];
int n;
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1 ){
printf("create socket error: %s(errno: %d)\n",strerror(errno),errno);
exit(0);
}
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(listenip);
servaddr.sin_port = htons(listenport);
if( bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) == -1){
printf("bind socket error: %s(errno: %d)\n",strerror(errno),errno);
return -1;
}
if( listen(listenfd, 10) == -1){
printf("listen socket error: %s(errno: %d)\n",strerror(errno),errno);
return -1;
}
printf("======waiting for client's request======\n");
while(1){
if( (connfd = accept(listenfd, (struct sockaddr*)NULL, NULL)) == -1){
printf("accept socket error: %s(errno: %d)",strerror(errno),errno);
continue;
}
/* create a new thread to handle this connection */
pthread_t tid = 0;
int rc = 0;
struct thread_arg *parg = malloc(sizeof(struct thread_arg));
if(NULL==parg) {
printf("error malloc: %s\n", strerror(errno));
return -1;
}
parg->socket = connfd;
parg->msg_handler = handler;
if(0 != (rc=pthread_create(&tid, NULL, thread_f, parg))) {
printf("%s: %s\n", __func__, strerror(rc));
}
printf(" create thread %u to handle connection %d \n", tid, connfd);
}
close(listenfd);
return 0;
}
/***************************
* fun: receive one message
* params: connfd - socket handle
* return: 0 - success;
* -1 - error
*
* **************************/
static int recv_one_message(int connfd, message_handler post_recv_one)
{
uint32_t msg_len = 0; /* message length */
/* recv length */
if(4 != recvn(connfd, &msg_len, 4)) { // something wrong
return -1;
}
msg_len = ntohl(msg_len);
/* recv body */
if(msg_len > 0x7FFFFFFF) {
printf("message body to large\n");
return -1;
}
char* buf = malloc(msg_len);/* allocate memory for message body*/
if(NULL == buf) {
printf("%s: malloc failed!\n", __func__);
return -1;
}
if(msg_len != recvn(connfd, buf, msg_len)) {
free(buf);
return -1;
}
if(0!=post_recv_one(connfd, buf, msg_len)) { // callback
free(buf);
return -1;
}
free(buf);
return 0;
}
/* thread to handle a connection */
static void * thread_f(void * arg)
{
printf(" enter thread %u\n", pthread_self());
struct thread_arg targ = *((struct thread_arg*)arg);
int connfd = targ.socket;
message_handler post_recv_one = targ.msg_handler;
free(arg);
int i = 0;
while(1) {
if(0 != recv_one_message(connfd, post_recv_one)) {
break;
}
printf("message : %d\n", i++);
}
close(connfd);
printf(" leave thread %u\n", pthread_self());
}
源码:测试例子 server.c,接收消息写入文件data中。
#include "tcputil.h"
#include <stdio.h>
/* callback called after one message received. */
int msg_handler(int fd, void* buf, uint32_t n)
{
char* msg = (char*)buf;
FILE* fp = fopen("data", "w");
if(NULL == fp) {
printf("%s\n", strerror(errno));
fclose(fp);
return -1;
}
if(n != fwrite(msg, 1, n, fp)) {
printf("write error:\n");
fclose(fp);
return -1;
}
fclose(fp);
return 0;
}
int main(int argc, char** argv)
{
start(0,6666, msg_handler);
}
源码:客户端程序 C#编写
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
SendTcpMsg(File.ReadAllBytes(@"F:\核心软件备份\TomatoWin2k3.SP2.R2.iso"));
}
static void SendTcpMsg(Byte[] msgBody)
{
Socket sock = null;
try
{
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Connect("172.16.35.135", 6666);
byte[] msgHead = BitConverter.GetBytes(IPAddress.HostToNetworkOrder(msgBody.Length));
sock.Send(msgHead);
sock.Send(msgBody);
}
catch (Exception ex)
{
Console.Write(ex.Message);
}
finally
{
if(sock!=null)
sock.Close();
}
}
}
}