TCP-proxy

background

Problem: HTTP server, including network, in another terminal within the network, the terminal may need to access the HTTP server.

Solution: a public network arrangement TCP proxy, HTTP server is also arranged a proxy (only active within the network to access external network).

 

1.  the IP fragmentation, the TCP stream and the application layer message extraction

  • UDP send large packets whether IP fragmentation?

meeting. IP layer recombinant. UDP header 8 bytes (source port, destination port, length, and checksum), is relatively simple.

 

  • TCP send large packages?

SYN packet carries MSS , transmitting the subsequent process stream, over MSS packets may be fragmented transmission.

 

  • Application layer extracted message?

    If a tcp more application layer message connected to long continuous transmission, the application layer protocol is required can be carried partitioning message. tcp stream oriented, Socket received two messages may be pushed together. The application layer needs to be able to flow into separate message.

2. socket option

setsockopt (socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # when a same address and port of the socket in the TIME_WAIT state, a new socket for the address and port occupies

setsockopt (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) #socket keepalive open

setsockopt (socket.SOL_TCP, socket.TCP_KEEPIDLE, 10) # for the first time before the probe TCP idle time

setsockopt (socket.SOL_TCP, socket.TCP_KEEPINTVL, 30) # send keepalive interval

setsockopt (socket.SOL_TCP, socket.TCP_KEEPCNT, 3) # determines the number of pre-break detection

3. Python Tcp reverse proxy

Process:

 

Realization: ServerA ServerB &

 

#!/usr/bin/env python
# -*- coding:UTF-8 -*-
import sys
import json
import time
import socket
import threading

SOCK = [0,0]

def ue_handler_close():
    try:
        try:
            SOCK[1].shutdown(2)
        except Exception as e:
            pass
        SOCK[1].close()
    except Exception as e:
        pass
    try:
        try:
            SOCK[0].shutdown(2)
        except Exception as e:
            pass
        SOCK[0].close()
    except Exception as e:
        pass

def ue_proxy_handler():
    while True:
        try:
            data = SOCK[0].recv(3000)

            if not data:
                ue_handler_close()
                break
            else:
                try:
                    SOCK[1].sendall(data)
                except Exception as e:
                    print("102 send to proxy error",str(e),str(Exception))
                    break

        except Exception as e: #ue recv exp
            ue_handler_close()
            break

def proxy_handler_close():
    try:
        try:
            SOCK[0].shutdown(2)
        except Exception as e:
            pass
        SOCK[0].close()
    except Exception as e:
        pass

    try:
        try:
            SOCK[1].shutdown(2)
        except Exception as e:
            pass
        SOCK[1].close()
    except Exception as e:
        pass

def proxy_proxy_handler():
    while True:
        try:
            data = SOCK[1].recv(1024)
            print("recv from proxy:%d"%len(data))

            if not data:
                proxy_handler_close()
                break
            else:
                try:
                    SOCK[0].sendall(data)
                except Exception as e:
                    print("proxy handler send to ue error",str(e),str(Exception))
                    break
        except Exception as e:
            print("proxy recv exp",str(e),str(Exception))
            proxy_handler_close()
            break

    print("#### proxy hander end ###")

if __name__ == '__main__':
    try:
        proxySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        proxySocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        proxySocket.bind(('0.0.0.0', 10099))
        proxySocket.listen(5)
        print("proxy server listenning ...")
    except Exception as e:
        print("001 socket error",str(e))
        exit(1)

    try:
        ueSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        ueSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        ueSocket.bind(('0.0.0.0', 10088))
        ueSocket.listen(5)
        print("ue server listenning ...")
    except Exception as e:
        print("002 socket error ue",str(e))
        exit(1)

    while True:
        SOCK = [0,0]
        print("begin******************************")
        try:
            proxyConn, addr = proxySocket.accept()
            print('proxy connected.')
            SOCK[1] = proxyConn

            ueConn, addr = ueSocket.accept()
            print('ue connected')
            SOCK[0] = ueConn

        except Exception as e:
            print('main socket error')
            try:
                ueSocket.close()
            except Exception as e:
                print(str(e))
            try:
                proxySocket.close()
            except Exception as e:
                print(str(e))
            continue

        ue_thread = threading.Thread(target=ue_proxy_handler)
        ue_thread.start()
        proxy_thread = threading.Thread(target=proxy_proxy_handler)
        proxy_thread.start()
        ue_thread.join()
        proxy_thread.join()

        print("end------------------------------")

 

 

 

C   proxy client

#include <stdlib.h> 

#include <stdio.h> 

#include <errno.h> 

#include <string.h> 

#include <netdb.h> 

#include <sys/types.h> 

#include <netinet/in.h> 

#include <sys/socket.h> 

#include <netinet/tcp.h>

#include <pthread.h>

 

#define PROXY_PORT  10099

#define RESTFUL_PORT  5000

#define BUFFER_SIZE 1024

 

int proxy_cli,restful_cli;

 

void close_sockets()

{

    if(0 != shutdown(proxy_cli,SHUT_RDWR)){

        //perror("shutdown proxy sock error");

    }else{

     printf("shutdown proxy\n");

    }

 

    if(0 != close(proxy_cli)){

        //perror("close proxy sock error");

    }else{

     printf("close proxy\n");

    }

    

    if(0 != shutdown(restful_cli,SHUT_RDWR)){

        //perror("shutdown restful sock error");

    }else{

     printf("shutdown restful\n");

    }

 

    if(0 != close(restful_cli)){

        //perror("close restful sock error");

    }else{

     printf("close restful\n");

    }

}

 

void proxy_handler()

{

    char recbuf[BUFFER_SIZE];

    int cnt;

    int sendcnt;

    while(1){

        cnt = recv(proxy_cli, recbuf, BUFFER_SIZE,0);

        if(cnt > 0)

        {

            //正常处理数据

            printf("recv from proxy %d\n",cnt);

            sendcnt = send(restful_cli, recbuf, cnt,0);

            

            if (sendcnt > 0){

                printf("send to restful %d\n",sendcnt);

            }

            else{

                printf("send to restful error %d\n",sendcnt);

                break;

            }

        }

        else

        {

            if((cnt<0) &&(errno == EAGAIN||errno == EWOULDBLOCK||errno == EINTR))

            {

                printf("proxy cnt < 0 and error:%d\n",errno);

                continue;//继续接收数据

            }

 

            if (0 == cnt){

             printf("proxy recv close.\n");

            }

            else{

             printf("proxy recv:%d\n",cnt);

            }

 

            break;//跳出接收循环

        }

    }

    printf("proxy close sockets\n");

    close_sockets();

    return;

}

 

void restful_handler()

{

    char recbuf[BUFFER_SIZE];

    int cnt;

    int sendcnt;

    while(1){

        cnt = recv(restful_cli, recbuf, BUFFER_SIZE,0);

        if(cnt > 0)

        {

            //正常处理数据

            printf("recv from restful %d\n",cnt);

            sendcnt = send(proxy_cli, recbuf, cnt,0);

            

            if (sendcnt > 0){

                printf("send to proxy %d\n",sendcnt);

            }

            else{

                printf("send to proxy error %d\n",sendcnt);

                break;

            }

        }

        else

        {

            if((cnt<0) &&(errno == EAGAIN||errno == EWOULDBLOCK||errno == EINTR))

            {

                printf("restful cnt < 0 and error:%d\n",errno);

                continue;//继续接收数据

            }

 

            if(0==cnt){

             printf("restful close\n");

            }else{

             printf("restful recv:%d\n",cnt);

            }

            break;//跳出接收循环

        }

    }

    printf("restful close sockets\n");

    close_sockets();

    return;

}

 

void setSocketOpt(int sk)

{

int keepalive = 1; // 开启keepalive属性

int keepidle = 6;  // 如该连接在6秒内没有任何数据往来,则进行探测

int keepinterval = 5; // 探测时发包的时间间隔为5 秒

int keepcount = 3; // 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.

setsockopt(sk,SOL_SOCKET,SO_KEEPALIVE, (void *)&keepalive , sizeof(keepalive ));

setsockopt(sk,SOL_TCP,TCP_KEEPIDLE, (void*)&keepidle , sizeof(keepidle ));

setsockopt(sk,SOL_TCP,TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval ));

setsockopt(sk,SOL_TCP,TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount ));

}

 

int main(int argc,char **argv)

{

if (1 == argc){

printf("usage: proxyproxy proxy_ip\n");

return 0;

}else{

printf("proxy ip:%s\n",argv[1]);

}

pthread_t thread1, thread2;

int tmp1, tmp2;

    struct sockaddr_in proxyaddr,restfuladdr;

    memset(&proxyaddr, 0, sizeof(proxyaddr));

    proxyaddr.sin_family = AF_INET;

    proxyaddr.sin_port = htons(PROXY_PORT);  

    proxyaddr.sin_addr.s_addr = inet_addr(argv[1]);

    

    memset(&restfuladdr, 0, sizeof(restfuladdr));

    restfuladdr.sin_family = AF_INET;

    restfuladdr.sin_port = htons(RESTFUL_PORT);

    restfuladdr.sin_addr.s_addr = inet_addr("127.0.0.1");

 

    while(1)

    {

     printf("**********************************************\n");

     proxy_cli = socket(AF_INET,SOCK_STREAM, 0);

     ///连接服务器,成功返回0,错误返回-1

     if (connect(proxy_cli, (struct sockaddr *)&proxyaddr, sizeof(proxyaddr)) < 0)

     {

     perror("connect proxy error");

     sleep(5);

     continue;

     }

     setSocketOpt(proxy_cli);

 

     restful_cli = socket(AF_INET,SOCK_STREAM, 0);

     if (connect(restful_cli, (struct sockaddr *)&restfuladdr, sizeof(restfuladdr)) < 0)

     {

     perror("connect restful error");

     shutdown(proxy_cli,SHUT_RDWR);

     close(proxy_cli);

     sleep(5);

     continue;

     }

     setSocketOpt(restful_cli);

 

     int ret_thrd1, ret_thrd2;

 

     ret_thrd1 = pthread_create(&thread1, NULL, (void *)&proxy_handler, NULL);

     ret_thrd2 = pthread_create(&thread2, NULL, (void *)&restful_handler, NULL);

 

     // 线程创建成功,返回0,失败返回失败号

     if (ret_thrd1 != 0) {

     printf("create proxy thread error\n");

     close_sockets();

     } else {

     printf("create proxy thread\n");

     }

 

     if (ret_thrd2 != 0) {

     printf("create restful thread error\n");

     close_sockets();

     } else {

     printf("create restful thread\n");

     }

 

     //同样,pthread_join的返回值成功为0

     tmp1 = pthread_join(thread1, NULL);

     //printf("thread1 return value(tmp) is %d\n", tmp1);

     if (tmp1 != 0) {

     printf("cannot join with thread1\n");

     }

     //printf("thread1 end\n");

 

     tmp2 = pthread_join(thread2, NULL);

     //printf("thread2 return value(tmp) is %d\n", tmp1);

     if (tmp2 != 0) {

     printf("cannot join with thread2\n");

     }

     //printf("thread2 end\n");

     printf("------------------------------------------------\n");

    }

 

    return 0;

}

 

延伸:

两个客户端之间创建隧道?

 

Guess you like

Origin www.cnblogs.com/sunnypoem/p/11368464.html