Linux中国 Linux中国门户站!
设为主页 设为主页
收藏本站 收藏本站
 
当前位置 :首页 ->Linux技术 ->系统管理 ->正文

一个简易的UDP Proxy程序

来源:Linux-cn.com 作者:Webmaster 时间:2007-05-05 点击: [收藏] [投稿]

1.为什么开发这个UDP程序

  网络状况如上文《一个简易的proxy程序的开发过程》。我们的socks代理是有权限的(相信很多公司都有这种情况存在)。写这个程序的时候,我还没有socks代理的权限,所以不能上OICQ。这让我感到很不方便。所以,我决定写一个UDP的代理程序来实现我上OICQ的愿望。原理同上文是一样的。只是在具体实现上略有所不同。

  先看看源代码,稍后再来解释。(由于这个版本是一个完全功能版,所以提供了很多sp.c没有提供的功能。)上文中提到过的部分,这里就不再次一一解释了。

  编译,运行是同上文所述相同的。

  但是,要注意UDP是没有连接的,所以程序的具体实现方式有所不同。

  来看程序:

#ifndef _DEBUG
signal(SIGINT, SIG_IGN);
#endif
signal(SIGHUP, SIG_IGN);
/* signal(SIGTERM, SIG_IGN); */
signal(SIGABRT, SIG_IGN);
signal(SIGSTOP, SIG_IGN);
signal(SIGCHLD, SIG_IGN);

  忽略上述信号,使程序以后台方式运行。

#ifndef _DEBUG
if (fork() != 0)
exit(0);

setsid();

for (i = 256; i >= 0; i --)
#endif

  如果不是DEBUG方式,程序以前台方式运行。

#ifdef _DEBUG
for (i = 256; i >= 3; i --)
#endif
close(i);

  关闭描述字。

bzero(&r_in, sizeof(r_in));
r_in.sin_family = AF_INET;
r_in.sin_port = htons(4000);
r_in.sin_addr.s_addr = inet_addr("192.168.103.97");

  192.168.103.97 是我机器的局域网IP地址。由于这个程序只是给我一个人使用的,所以没有在这上面处理得更灵活一些。:-)

fd_listen = socket(PF_INET, SOCK_DGRAM, 0);
if (fd_listen < 0) {
p_error("socket1 error");
exit(1);
}

  UDP的socket描述字是这样子建立的。

fcntl(fd_listen, F_SETFL, O_NONBLOCK);
fcntl(fd_tran, F_SETFL, O_NONBLOCK);

  将这两个监听端口的socket方式设置为非阻塞的。

if (FD_ISSET(fd_listen, &fdset)) {
alen = sizeof(r_in);
data_len = recvfrom (fd_listen, buffer, sizeof(buffer), 0,
(struct sockaddr *)&r_in, &alen);
if (data_len <= 0) {
p_error("socket closed by remote client");
close(fd_listen);
close(fd_tran);
exit(0);
}
#ifdef _DEBUG
ip = inet_ntoa(r_in.sin_addr.s_addr);
printf("received from %s , socket id: %d", ip, fd_listen);
p_log("received from inner:", 23);
/* sizeof("received from inner:"); */
p_log(buffer, data_len);
#endif

if (sendto(fd_tran, (char *)buffer, data_len, 0,
(struct sockaddr *)&r_out, sizeof(r_out)) <=0 ) {
p_error("cann't send to remote server");
close(fd_tran);
close(fd_listen);
exit(0);
}
#ifdef _DEBUG
ip = inet_ntoa(r_out.sin_addr.s_addr);
printf("send to %s", ip);
#endif

}

  对于UDP来说,用的是recvfrom和sendto. 在程序中同时加入了recvfrom时的客户端地址,便于在调试的时候来检查。同时,这里面也有一些调试的信息,比如,输出接收到的字符串,客户端地址等等。

else if (FD_ISSET(fd_tran, &fdset)) {
alen = sizeof(stmp);
data_len = recvfrom (fd_tran, buffer, sizeof(buffer), 0,
(struct sockaddr *)&stmp, &alen);
if (data_len <= 0) {
p_error("socket closed by remote server");
close(fd_listen);
close(fd_tran);
exit(0);
}
#ifdef _DEBUG
ip = inet_ntoa(stmp.sin_addr.s_addr);
printf("received from %s , socket id: %d", ip, fd_tran);
p_log("received from outer:", 23);
/* sizeof("received from outer:"); */
p_log(buffer, data_len);
#endif

if (sendto(fd_listen, (char *)buffer, data_len, 0,
(struct sockaddr *)&r_in,
sizeof(r_in)) <=0 ) {
p_error("cann't send to remote server");
close(fd_tran);
close(fd_listen);
exit(0);
}
#ifdef _DEBUG
ip = inet_ntoa(r_in.sin_addr.s_addr);
printf("send to %s", ip);
#endif

}

  这一段是一样的。所不同的是,从fd_tran中读出来写回到fd_listen中去。

  两个日志函数的说明。

void
p_error(const char * err_msg)
{
FILE * fp;

#ifdef _DEBUG
printf("%s", err_msg);
#endif

fp = fopen(ERRLOG, "a");
if (fp == NULL)
return;
fprintf(fp, "%s", err_msg);
fclose(fp);
}

  调试的时候,将错误信息输出到标准输出上。

  非调试状态的时候,将错误信息输出到/usr/tmp/下的一个隐藏文件中。

void
p_log(const char * buffer, int len)
{
FILE * fp;

fp = fopen(LOGFILE, "ab");
if (fp == NULL)
return;
fwrite(buffer, len, 1, fp);

 如果您对本文有任何疑问或者建议,请到讨论区发表您的意见: >> 论坛入口 <<



上一篇:一个简易的proxy程序的开发过程(1)   下一篇:使自己的程序成为后台运行的守护进程

文章评论】 【收藏本文】 【推荐好友】 【打印本文】 【我要投稿】 【论坛讨论
更多相关文章
Power by linux-cn.com 粤ICP备05006655号