TCPプロキシ

背景

問題: HTTPのサーバー、ネットワークを含むが、ネットワーク内の他の端末では、端末がアクセスする必要があるかもしれHTTPのサーバーを。

ソリューション:パブリックネットワークの配置のTCP プロキシ、HTTPのサーバも(外部ネットワークにアクセスするために、ネットワーク内のみ有効)プロキシを配置されています。

 

1.  IPのフラグメンテーション、TCPのストリームとアプリケーション層メッセージ抽出

  • UDPは、かどうか、大きなパケットを送信IPの断片化?

ウィル。IPの層の組換え体。UDP ヘッダ8 バイト(元ポート、宛先ポート、長さ、およびチェックサム)、比較的簡単です。

 

  • TCPは大きなパッケージを送信しますか?

SYNのパケットが搬送するMSSをかけて、その後のプロセスストリームを送信し、MSSのパケットが送信を断片化することができます。

 

  • アプリケーション層はメッセージを抽出しますか?

    場合 TCP 長い連続送信に接続された複数のアプリケーション層のメッセージ、アプリケーション層プロトコルは、パーティショニング・メッセージを実施することができる必要とされます。TCP ストリーム指向、ソケットは、2件のメッセージが一緒にプッシュすることができる受信しました。アプリケーション層は、別個のメッセージ内に流入できるようにする必要があります。

2.  ソケットオプション

setsockopt(1 socket.SOL_SOCKET、socket.SO_REUSEADDR) #の同じアドレスおよびポートソケットTIME_WAITの状態は、新しいソケットアドレスとポートのが占有します

setsockopt(socket.SOL_SOCKET、socket.SO_KEEPALIVE、1) #socketのキープアライブオープン

setsockopt(socket.SOL_TCP、socket.TCP_KEEPIDLE、10) #プローブの前に初めてTCP アイドル時間

setsockopt(socket.SOL_TCP、socket.TCP_KEEPINTVL、30) #は、 キープアライブインターバルを送ります

setsockopt(socket.SOL_TCP、socket.TCP_KEEPCNT、3) #は、 事前断線検出の数を決定します

3.  PythonのTcpのリバースプロキシ

プロセス:

 

実現:サーバーAサーバーB&

 

#!/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;

}

 

延伸:

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

 

おすすめ

転載: www.cnblogs.com/sunnypoem/p/11368464.html