实现tcp代理

目录

一、使用go实现(协程)

二、使用C实现(多进程)


一、使用go实现(协程)

注:对于每个连接,开两个协程分别处理读、写。

技术点:多协程、go网络编程、go io库。

package main

import (
	"io"
	"log"
	"net"
	"os"
)

func main() {
	if len(os.Args) < 3 {
		log.Fatal("./main localaddr remoteaddr")
	}
	localaddr := os.Args[1]
	remoteaddr := os.Args[2]

	l, err := net.Listen("tcp", localaddr)
	if err != nil {
		log.Fatal(err)
	}
	for {
		conn, err := l.Accept()
		if err != nil {
			log.Println("err:", err)
		} else {
			go Serve(conn, remoteaddr)s
		}
	}
}

func Serve(conn1 net.Conn, remoteAddr string) {
	defer conn1.Close()

	conn2, err := net.Dial("tcp", remoteAddr)
	if err != nil {
		log.Println("err:", err)
	}
	defer conn2.Close()

	go io.Copy(conn1, conn2)
	io.Copy(conn2, conn1)
}

二、使用C实现(多进程)

注:对于每个连接,开两个进程分别处理读、写。

技术点:linux 网络编程、linux进程与进程回收。

来源:tcporoxy

#include<netdb.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<errno.h>
#include<sys/socket.h>
#include<sys/types.h>
#include <sys/wait.h>
#include<signal.h>


#define bool int
#define TRUE 1
#define FALSE 0
#define OK 1
#define BUF_SIZE 1024

int remote_port, local_port;
int listen_fd;
char *remote_host;
struct sockaddr_in server_addr;

int create_server(int local_port);
int server_loop();
int handler_client(int connfd);
int create_conn_server(char* remote_host, int remote_port);
int redirect_data(int srcfd, int dstfd);
void sigchld_handler(int signal);

int main(int argc, char *argv[]) {
	int opt;
	char **pptr;
	bool show_version_flag = FALSE;
	bool remote_host_flag = FALSE;
	bool local_port_flag = FALSE;
	bool remote_port_flag = FALSE;
	char str[100];
	struct hostent *host_s;

	/*
	 * v For version
	 * l For localhost port
	 * h For remote ip
	 * p For remote port
	 */

	while ((opt = getopt(argc, argv, "vl:h:p:")) != -1) {
		switch (opt) {
		case 'v':
			show_version_flag = TRUE;
			break;
		case 'h':
			remote_host_flag = TRUE;
			remote_host = optarg;
			break;
		case 'l':
			local_port_flag = TRUE;
			local_port = atoi(optarg);
			break;
		case 'p':
			remote_port_flag = TRUE;
			remote_port = atoi(optarg);
			break;
		default:
			break;
		}
	}

	if (show_version_flag) {
		printf("TcpProxy Version 1.1\n");
	}

	if (!(local_port_flag && remote_port_flag && remote_port_flag)) {
		printf("Usage: tcpproxy -l 8080 -h 127.0.0.1 -p 80\n");
		exit(0);
	} else {
		printf("tcpproxy -l %d -h %s -p %d\n", local_port, remote_host,
				remote_port);
	}
	signal(SIGCHLD, sigchld_handler); // prevent ended children from becoming zombies
	if (create_server(local_port) == -1) {
		printf("create server() error.Exiting...");
		exit(-1);
	}
	server_loop();
	return 0;
}

void sigchld_handler(int signal) {
	while (waitpid(-1, NULL, WNOHANG) > 0)
		;
}

int create_server(int local_port) {
	listen_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (listen_fd == -1) {
		printf("socket() error %d : %s\n", errno, strerror(errno));
		return -1;
	}
	server_addr.sin_port = htons(local_port);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY );
	if ((bind(listen_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)))
			== -1) {
		printf("bind() error %d : %s \n", errno, strerror(errno));
		return -1;
	}
	if ((listen(listen_fd, 20)) == -1) {
		printf("listen() error %d : %s \n", errno, strerror(errno));
		return -1;
	}
	return listen_fd;
}

int server_loop() {
	int connfd;
	while (1) {
		connfd = accept(listen_fd, (struct sockaddr *) NULL, NULL );
		if (connfd == -1) {
			printf("accept() error %d : %s\n", errno, strerror(errno));
			return -1;
		}
		if (fork() == 0) {
			close(listen_fd);
			handler_client(connfd);
			exit(0);
		}
		close(connfd);
	}
	return OK;
}

int handler_client(int connfd) {
	int client_fd;
	client_fd = create_conn_server(remote_host, remote_port);
	if (fork() == 0) {
		redirect_data(connfd, client_fd);
		exit(0);
	}
	if (fork() == 0) {
		redirect_data(client_fd, connfd);
		exit(0);
	}
	close(connfd);
	close(client_fd);
	return OK;
}

int create_conn_server(char* remote_addr, int remote_port) {
	int client_fd;
	struct sockaddr_in client_addr;
	client_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (client_fd == -1) {
		printf("socket errno %d : %s \n", errno, strerror(errno));
		return -1;
	}
	client_addr.sin_family = AF_INET;
	client_addr.sin_port = htons(remote_port);
	inet_pton(AF_INET, remote_addr, &client_addr.sin_addr);
	if ((connect(client_fd, (struct sockaddr *) &client_addr,
			sizeof(client_addr))) < 0) {
		printf("connect error %d : %s \n", errno, strerror(errno));
		return -1;
	}
	return client_fd;
}

int redirect_data(int srcfd, int dstfd) {
	char buf[BUF_SIZE];
	int n;
	while ((n = recv(srcfd, buf, BUF_SIZE, 0)) > 0) {
		send(dstfd, buf, n, 0);
	}
	close(srcfd);
	close(dstfd);
	return OK;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值