(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
参考:https://github.com/vakuum/tcptunnel
参考:https://zhihu.com/question/48161206
下面是写linux下tcp转发编程时,遇到的几个知识点,记录如下:
1. fork:创建子进程通信
服务端接受到请求后,fork出子进程,然后使用子进程与client通信
while(true)
{
// accept link from client
...
// muti processes
int forkid = fork();
if (forkid == 0)
{
// main process
close(clifd);
continue;
}
else if (forkid < 0)
{
fprintf(stdout, "error occur on fork");
continue;
}
// child process, communicate with client
close(servfd);
}
2. mmap:进程间共享内存shared memory
mmap可以建立一个映射,用于进程间的内存数据共享。
// share memory bettwen process
struct sockaddr_in *pLocal = (sockaddr_in*)mmap(0, sizeof(sockaddr_in), PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
struct sockaddr_in &local = *pLocal;
while(true)
{
...
// child process: update data
local = cli;
...
munmap(pLocal, sizeof(sockaddr_in));
break;
}
3. setsockopt:设置socket超时参数
消息通信时,时常会遇到通信线路异常,或者超时等各类情况,recv接受消息时设置超时通常会是必不可少的。
// set time out
struct timeval tv;
tv.tv_sec = 15;
tv.tv_usec = 0;
setsockopt(clifd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(tv));
4. select: 检查多个socket变化
select支持检查多个socket的变化,可以检查到这些socket是否有数据过来;
fd_set fdset;
while(true)
{
FD_ZERO(&fdset);
FD_SET(clifd, &fdset);
FD_SET(servfd, &fdset);
int maxfd = clifd > servfd ? clifd+1 : servfd + 1;
if ((rt=select(maxfd, &fdset, NULL, NULL, &tv)) <= 0)
break;
if (FD_SET(clifd, &fdset)){
...
}
if (FD_SET(servfd, &fdset)){
...
}
}
5. signal: 使用signal关闭主进程对子进程的关注
消息中主进程并不关注子进程是否处理完毕,是否已结束。如果不做作何处理,子进程会成为defunct状态。在主进程提前声明可以避免这种情况。
#include <sys/types.h>
#include <sys/wait.h>
...
// main process
signal(SIGCHLD,SIG_IGN);
...
6. 允许端口重复绑定
允许端口被重复绑定的意义有两个:第一个是解决结束进程时,端口还会被占用一会,此时启动会失败;另一个意义在于可以通过启动多进程,形成多个进程同时服务的效果。
int opt = 1;
setsockopt(srvfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
setsockopt(srvfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(opt));
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)