首页 服务器 编程 必备知识 搜索引擎 圩日手册
站内搜索
最近浏览
推荐文章
热文排行

简单代理服务器C代码实现(SOLARIS)


*
** 编写:无可非议
** 来源:WWW.20CN.NET
** 注意:请注明转贴来源
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/stat.h>

int m_MainId = 0; //主进程ID
int m_ListenSocket = 0; //侦听套接字
char m_ConnectAddr[256] = {0}; //目标地址
char m_ConnectPort[256] = {0}; //目标端口

/*
** 函数名称: GetListenSocket
** 函数功能: 生成侦听套接字
** 传入参数: Port : 侦听端口
** 传出参数: 无
** 引用函数: 无
** 返回值 : 侦听套接字,为0时表示生成套接字失败,其他为套接字句柄
** 备注 : 无
*/
int GetListenSocket(int Port)
{
struct sockaddr_in m_LisAddr = {0};
int m_Socket = 0;
int m_AddrLen = sizeof(struct sockaddr_in);

//配置端口信息
m_LisAddr.sin_family = AF_INET;
m_LisAddr.sin_port = htons(Port);
m_LisAddr.sin_addr.s_addr = INADDR_ANY;

//创建套接字
if ((m_Socket = socket(AF_INET,SOCK_STREAM,0)) < 0 )
{
//创建套接字失败
return 0;
}

//绑定套接字
if(bind(m_Socket, (sockaddr*)&m_LisAddr , m_AddrLen) < 0 )
{
//绑定套接字失败
close(m_Socket);
return 0;
}

//侦听套接字
if(listen(m_Socket,5))
{
//侦听套接字失败
close(m_Socket);
return 0;
}

//侦听套接字生成成功
return m_Socket;
}

/*
** 函数名称: GetConnectSocket
** 函数功能: 生成连接套接字
** 传入参数: pServerAddr : 连接地址 pServerPort : 连接端口
** 传出参数: 无
** 引用函数: 无
** 返回值 : 连接套接字,为0时表示生成套接字失败,其他为套接字句柄
** 备注 : 无
*/
int GetConnectSocket(char* pServerAddr,char* pServerPort)
{
struct sockaddr_in m_ServerAddr = {0};
int m_AddrLen = sizeof(struct sockaddr_in);
int m_Socket = 0;

//初始化连接信息
m_ServerAddr.sin_addr.S_un.S_addr = inet_addr(pServerAddr);
m_ServerAddr.sin_port = htons(atoi(pServerPort));
m_ServerAddr.sin_family = AF_INET;

//创建发送套接字
m_Socket = socket(AF_INET,SOCK_STREAM,0);
if(m_Socket <= 0)
{
//失败
return NULL;
}

//连接客户计算机
if(connect(m_Socket,(sockaddr*)&m_ServerAddr,m_AddrLen) < 0 )
{
close(m_Socket);
return NULL;
}

//连接成功
return m_Socket;
}

/*
** 函数名称: TransSocket
** 函数功能: 完成套接字数据转发
** 传入参数: m_SendSocket : 发送套接字 m_RecvSocket : 接收套接字
** 传出参数: 无
** 引用函数: 无
** 返回值 : 无
** 备注 : 逆反完成全双工
*/
void TransSocket(int m_SendSocket,int m_RecvSocket)
{
char m_Buf[512 * 1024] = {0};
int ret = 0;
fd_set readset;
struct timeval tm = {0};
tm.tv_sec = 3600 * 24;

FD_ZERO(&readset);
FD_SET(m_RecvSocket,&readset);

while(1)
{
if((select(m_RecvSocket + 1,&readset,NULL,NULL,&tm)
<= 0))
{
//出错
break;
}
if(!FD_ISSET(m_RecvSocket,&readset)) continue;

ret = recv(m_RecvSocket,m_Buf,512 * 1024 - 1,0);
if(ret < 0)
{
//出错
break;
}
send(m_SendSocket,m_Buf,ret,0);
}
close(m_SendSocket);
close(m_RecvSocket);
}

/*
** 函数名称: SocketTrans
** 函数功能: 工作主函数,完成数据转发,新进程启动
** 传入参数: m_SendSocket : 发送套接字 m_RecvSocket : 接收套接字
** 传出参数: 无
** 引用函数: 无
** 返回值 : 无
** 备注 : 逆反完成全双工
*/
void SocketTrans()
{
struct sockaddr_in m_WorkAddr = {0};
int m_191Socket = 0;
int m_147socket = 0;
int m_WorkAddrLen = 0;

//开始任务执行
while(1)
{
//接受147的连接
m_WorkAddrLen = sizeof(struct sockaddr_in);
m_147socket = accept(m_ListenSocket,
(sockaddr*)&m_WorkAddr , &m_WorkAddrLen);

//检查套接字合法性
if(m_147socket < 0) continue;

//连接191
m_191Socket = GetConnectSocket(m_ConnectAddr,m_ConnectPort);
if(m_191Socket == NULL)
{
close(m_147socket);
continue;
}

int ret = fork();
if(ret < 0)
{
//建立新进程失败
printf("致命错误,无法建立新进程!\n");
fflush(stdout);
close(m_191Socket);
close(m_147socket);
break;
}
else if(ret == 0)
{
//关闭原来端口
close(m_ListenSocket);

//建立二次子进程,防止僵尸进程
ret = fork();
if(ret < 0)
{
close(m_191Socket);
close(m_147socket);
_exit(0);
}
else if(ret == 0)
{
//接收进程
TransSocket(m_191Socket,m_147socket);
_exit(0);
}
ret = fork();
if(ret < 0)
{
close(m_191Socket);
close(m_147socket);
_exit(0);
}
else if(ret == 0)
{
//发送进程
TransSocket(m_147socket,m_191Socket);
_exit(0);
}
close(m_191Socket);
close(m_147socket);
_exit(0);
}

//等待子线程结束
close(m_191Socket);
close(m_147socket);
waitpid(ret,NULL,0);
}
}

/*
** 函数名称: sig_usr
** 函数功能: 进程信号处理函数
** 传入参数: 无
** 传出参数: 无
** 引用函数: 无
** 返回值 : 无
** 备注 : 处理进程终止事件
*/
static void sig_usr(int signo)
{
close(m_ListenSocket);
if(m_MainId == getpid())
kill(0,SIGKILL);
exit(0);
}

static void sig_ign(int signo)
{
fprintf(stderr,"signal %d catched ,ignoring\n",signo);
}

int daemon_init()
{
pid_t pid;
if((pid=fork())<0){
return -1;
}else if(pid!=0){
exit(0);
}
setsid();
umask(0);
return 0;
}

/*
** 函数名称: main
** 函数功能: 进程主函数
** 传入参数: 无
** 传出参数: 无
** 引用函数: MakeFilePath,GetMyInitInfo,SocketTrans
** 返回值 : 无
** 备注 : 为客户接收进程主函数
*/
int main(int argc,char* argv[])
{
//检查参数合法性
if(argc != 4)
{
printf("格式:本地端口 目的地址 目的端口\n");
fflush(stdout);
return 0;
}

daemon_init();

//登记信号事件
signal(SIGTERM,sig_usr);
signal(SIGINT,sig_usr);
signal(SIGQUIT,sig_usr);
signal(SIGPIPE,sig_ign);
signal(SIGALRM,sig_ign);
signal(SIGQUIT,sig_ign);
signal(SIGFPE,sig_ign);
signal(SIGILL,sig_ign);
signal(SIGPIPE,sig_ign);
signal(SIGSEGV,sig_ign);
signal(SIGTRAP,sig_ign);
signal(SIGTSTP,sig_ign);

//取参数
strcpy(m_ConnectAddr,argv[2]);
strcpy(m_ConnectPort,argv[3]);

//获取侦听套接字
m_ListenSocket = GetListenSocket(atoi(argv[1]));
if(m_ListenSocket == 0)
{
printf("侦听端口[%s]失败!\n",argv[1]);
fflush(stdout);
return 0;
}

m_MainId = getpid();
//启动文件接收侦听线程
SocketTrans();
close(m_ListenSocket);
return 0;
}


===============================================
本文版权属20CN网络安全小组及其作者所有,如有转载,请保持文章完整性并注明出处
文章类型:原创
[wangjy17908]
添加时间:2007-08-03
版权所有(C)2005-2015