-1

C プログラムで 2 つのポート (ポート x に行くものはすべてポート y に行き、その逆) をマップしたいのですが、このプログラムを書きましたが、動作しません。これは私のコードです:

int recv_all_nonblock(int sockfd,char* buff,int buffersize)
{
    int numbytes;
    if ((numbytes = recv(sockfd, buff, buffersize-1, MSG_NOSIGNAL|MSG_DONTWAIT)) <= 0)
    {
    perror("recv");
    }
    else if( numbytes>0)
    {
    buff[numbytes] = '\0';
    }

    return numbytes;
}


int sendall(int sockfd, char *buf, int *len)
{
    int total = 0;        // how many bytes we've sent
    int bytesleft = *len; // how many we have left to send
    int n=0;
    while(total < *len)
    {
    n = send(sockfd, buf+total, bytesleft, MSG_NOSIGNAL|MSG_DONTWAIT);
    if (n == -1) { break; }
    total += n;
    bytesleft -= n;
    }

    *len = total; // return number actually sent here

    return n==-1?-1:0; // return -1 on failure, 0 on success
}


int Connect_To_Remote(char *Addr,char* PORT)
{
    int sockfd;
    struct addrinfo hints, *servinfo=NULL, *p=NULL;
    int rv;
    char s[INET6_ADDRSTRLEN];



    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    while (p==NULL)
    {
    sleep(5);
    while((rv = getaddrinfo(Addr, PORT, &hints, &servinfo)) != 0)
    {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        sleep(5);
    }

    for(p = servinfo; p != NULL; p = p->ai_next)
    {
        if ((sockfd = socket(p->ai_family, p->ai_socktype,p->ai_protocol)) == -1)
        {
        perror("client: socket");
        continue;
        }

        if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1)
        {
        close(sockfd);
        perror("client: connect");
        continue;
        }

        break;
    }

    if (p == NULL)
    {
        fprintf(stderr, "client: failed to connect\n");
    }
    }

    inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),s, sizeof s);
    printf("client: connecting to %s\n", s);

    freeaddrinfo(servinfo); // all done with this structure
    return sockfd;

}
int recv_all(int sockfd,char* buff,int buffersize)
{
    int numbytes;
    fd_set readfd_set;
    struct timeval recvwait;

    recvwait.tv_sec=10;
    recvwait.tv_usec=0;
    FD_ZERO(&readfd_set);
    FD_SET(sockfd, &readfd_set);
    if(select(sockfd+1, &readfd_set, NULL, NULL, &recvwait) <= 0)
    {
    perror("wait for recieve error:");
    }
    else
    {
    if ((numbytes = recv(sockfd, buff, buffersize-1, MSG_NOSIGNAL|MSG_DONTWAIT)) == -1)
    {
        perror("recv");
    }
    else if( numbytes>0)
    {
        buff[numbytes] = '\0';
    }

    return numbytes;
    }

    return 0;
}

void *Port_Mapper()
{
    int sockfd,newfd;  // listen on sock_fd, new connection on new_fd
    struct addrinfo hints, *servinfo, *tmpaddrinfo;
    struct sockaddr_storage their_addr; // connector's address information
    socklen_t sin_size;
    int rv;
    int yes=1;
    int ret=0;

    memset(&hints, 0, sizeof (hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; // use my IP

    while (1)
    {
    if ((rv = getaddrinfo(NULL, MapPort, &hints, &servinfo)) != 0)
    {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        sleep(2);
    }
    else
    {
        break;
    }
    }

    while (1)
    {
    for(tmpaddrinfo = servinfo; tmpaddrinfo != NULL; tmpaddrinfo = tmpaddrinfo->ai_next)
    {
        if ((sockfd = socket(tmpaddrinfo->ai_family,tmpaddrinfo->ai_socktype,tmpaddrinfo->ai_protocol)) == -1)
        {
        perror("server: socket");
        continue;
        }
        if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,sizeof(int)) == -1)
        {
            perror("setsockopt");
            exit(1);
        }
        if (bind(sockfd, tmpaddrinfo->ai_addr, tmpaddrinfo->ai_addrlen) == -1) {
        close(sockfd);
        perror("server: bind");
        continue;
        }

        break;
    }
    if (tmpaddrinfo == NULL)
    {
        fprintf(stderr, "server: failed to bind\n");
        sleep(1);
    }
    else
    {
        break;
    }
    }
    freeaddrinfo(servinfo); // all done with this structure
    if (listen(sockfd, MAXLISTENQ) == -1)
    {
    perror("listen");
    exit(1);
    }
    int bufpoint=0;
    printf("server: waiting for connections...\n");
    while(1)
    {  // main accept() loop
    char buff[MAX_SOCK_BUFFER];
    char buff2[MAX_SOCK_BUFFER];
    ret=0;
    int sockfdweb=0;
    sin_size = sizeof (their_addr);
    printf("mapping server: going to  accept connections...\n");
    newfd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
    printf("\n\nmapping server: connections accepted:%d\n",newfd);

    sockfdweb=Connect_To_Remote("192.168.1.10","80");
    if (sockfdweb<0)
    {
        printf("can not connect to %s\n","192.168.1.10");
        break;
    }
      while(1)
    {



        memset(buff,0,sizeof(buff));
        ret=recv_all_nonblock(newfd,buff,MAX_SOCK_BUFFER);
printf("recved from client1,%d\n",ret);
        if (ret<=0)
        {
        perror("recieve error from browser:");
        close(newfd);
        sin_size = sizeof (their_addr);
        printf("mapping server: going to  accept connections...\n");
        newfd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
          ret=recv_all_nonblock(newfd,buff,MAX_SOCK_BUFFER);
    printf("recved from client10,%d\n",ret);
        if (ret<=0)
        {
            perror("recieve error from browser:");
            close(newfd);
            sin_size = sizeof (their_addr);
            printf("mapping server: going to  accept connections...\n");
            newfd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
        }
        else if(ret>0)
        {
    printf("recved from client0\n");
    printf("%s\n",buff);
            if (sendall(sockfdweb,buff,&bufpoint)<0)
            {
            printf("can not send data to %s\n","192.168.1.10");
            }
    printf("send to 80,0\n");

        }

        }
        else if(ret>0)
        {
printf("recved from client\n");
    printf("%s\n",buff);
        if (sendall(sockfdweb,buff,&bufpoint)<0)
        {
            printf("can not send data to %s\n","192.168.1.10");
        }
    printf("send to 80\n");

        }

        memset(buff2,0,sizeof(buff2));
        ret=recv_all_nonblock(sockfdweb,buff2,MAX_SOCK_BUFFER);
printf("recv from 80...%d\n",ret);
        if (ret<=0)
        {
        close(sockfdweb);
        sockfdweb=Connect_To_Remote("192.168.1.10","80");
        if (sockfdweb<0)
        {
            printf("can not connect to %s\n","192.168.1.10");
            break;
        }
        ret=recv_all_nonblock(sockfdweb,buff2,MAX_SOCK_BUFFER);
    printf("recv from 80.9..%d\n",ret);
        if (ret<=0)
        {
            close(sockfdweb);
            sockfdweb=Connect_To_Remote("192.168.1.10","80");
            if (sockfdweb<0)
            {
            printf("can not connect to %s\n","192.168.1.10");
            break;
            }

        }
        else if (ret>0)
        {
    printf("recved from 809\n");
            if (sendall(newfd,buff2,&ret)<0)
            {
            printf("can not send data to %s\n","192.168.1.10");
            }
    printf("send to client9\n");

        }

        }
        else if (ret>0)
        {
printf("recved from 80\n");
        if (sendall(newfd,buff2,&ret)<0)
        {
            printf("can not send data to %s\n","192.168.1.10");
        }
printf("send to client\n");

        }


    }

    }
    return 0;
}

int main()
{
.
.
.
.
    pthread_attr_init (&attr);
    pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
    pthread_create(&portmapper_threadid,&attr,Port_Mapper,NULL);
    pthread_attr_destroy (&attr);
.
.
.
.
}

Port_Mapper 関数に「printf」を追加し、ブラウザーで Web を要求したときに何が起こるかを追跡するために、次のように変更を加えました。

http://127.0.0.1:8090/

ブラウザを 2 ~ 3 回更新したプログラムの出力は次のとおりです。

マッピング サーバー: 受け入れた接続:5
クライアント: 192.168.1.10 に接続 クライアント
から受信
1,360 クライアントから受信
GET /1/ HTTP/1.1
ホスト: 127.0.0.1:8090
ユーザー エージェント: Mozilla/5.0 (X11; Linux i686; rv :6.0.2) Gecko/20100101 Firefox/6.0.2
Accept: text/html,application/xhtml+xml,application/xml;q=0.9, / ;q=0.8
Accept-Language: en-us,en;q= 0.5
Accept-Encoding: gzip、deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
接続: キープアライブ
Cache-Control: max-age=0

80 に送信
recv:
80...-1 からリソースが一時的に使用不可 recv
クライアント: 192.168.1.10 に接続中 recv: 80.9..-1 から
リソースが一時的に使用不可recv クライアント: 192.168.1.10 に接続中 recv: クライアント1 から 受信されたリソースが 一時的に使用不可,-1 ブラウザからの受信エラー:: リソースが一時的に利用できません マッピング サーバー: 接続を受け入れようとしています... client10,360 から受信しまし た client0 から受信しました GET /1/ HTTP/1.1 ホスト: 127.0.0.1:8090 ユーザー エージェント: Mozilla/ 5.0 (X11; Linux i686; rv:6.0.2) Gecko/20100101 Firefox/6.0.2 Accept: text/html,application/xhtml+xml,application/xml;q=0.9, /











;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
接続: keep -alive
キャッシュ制御: max-age=0

send to 80,0
recv: リソースが一時的に利用できません
80...0
クライアントからの recv: 192.168.1.10 に
接続 しています recv : リソースが一時的に利用できませんclient1,-1 ブラウザからエラーを受信しました:: リソースが一時的に利用できません マッピング サーバー: 接続を受け入れようとしています... recv: クライアントからリソースを一時的に利用できません でした10,-1ブラウザからエラーを受信しまし た:: リソースが一時的に利用できません... recv: リソースが一時的に利用できません recv from 80...0












クライアント: 192.168.1.10 に接続 中recv :
リソースが一時的に利用不可 80.9 ..-
1 から recv Mozilla/5.0 (X11; Linux i686; rv:6.0.2) Gecko/20100101 Firefox/6.0.2 Accept: text/html,application/xhtml+xml,application/xml;q=0.9, / ;q=0.8 Accept-言語: en-us,en;q=0.5 Accept-Encoding: gzip, deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 接続: キープアライブ










80 に送信
recv:
80...-1 からリソースが一時的に使用不可 recv
クライアント: 192.168.1.10 に接続中 recv: 80.9..-1 から
リソースが一時的に使用不可recv クライアント: 192.168.1.10 に接続中 recv: クライアント1 から 受信されたリソースが 一時的に使用不可,-1 ブラウザからの受信エラー:: リソースが一時的に利用できない マッピング サーバー: 接続を受け入れようとしています...





プログラムがブラウザからデータを正しく受信していることがわかりますが、データを Web サーバーに送信し、Web サーバーからデータを受信しようとすると、常にエラーが発生し、Web サーバーからデータを受信しません。

send to 80
recv: リソースが一時的に利用できません
recv from 80...-1

Web サーバーは問題なく正しく動作していると言わざるを得ません。
私の問題は何ですか?

4

1 に答える 1

0

あなたのコードは、このような簡単なタスクに対して非常に複雑です。多くの引用を簡略化できます。この(疑似)コードを参照してください。

void mapper()
{
    int server_socket = create_server_socket();

    for (;;)
    {
        int incomming_socket = accept(server_socket);

        int web_server_socket = connect_to_webserver();

        make_socket_nonblocking(incomming_socket);
        make_socket_nonblocking(web_server_socket);

        for (;;)
        {
            int disconnected = 0;

            FD_ZERO(&read_set);

            FD_SET(incomming_socket, &read_set);
            FD_SET(web_server_socket, &read_set);

            select(max_socket + 1, &read_set, NULL, NULL, NULL);

            if (FD_ISSET(incomming_socket, &read_set))
            {
                disonnected = recv_and_send(incomming_socket, web_server_socket);
            }
            if (!disconnected && FD_ISSET(web_server_socket, &read_set))
            {
                disconnected = recv_and_send(web_server_socket, incomming_socket);
            }

            if (disconnected)
                break;
        }

        close(web_server_socket);
        close(incomming_socket);
    }
}

int recv_and_send(from_socket, to_socket)
{
    char buffer[1024];

    for (;;)
    {
        len = recv_all(from_socket, buffer, sizeof(buffer));
        if (len < 0)
            return 1;  /* Disconnect */
        if (len == 0)
            break;  /* No more to read for now */

        if (send_all(to_socket, buffer, len) < 0)
            return 1;  /* Disconnect */
    }

    return 0;
}

int recv_all(socket_fd, char *buffer, const size_t buflen)
{
    size_t total_recv = 0;
    size_t remaining_len = buflen;

    while (remaining_len > 0)
    {
        ssize_t len = recv(socket_fd, buffer + total_recv, remaining_len);
        if (len < 0)
        {
            if (errno == EWOULDBLOCK)
                break;  /* No more to read at the moment */
            return -1;  /* An error */
        }
        if (len == 0)
            break;  /* Connection closed */

        total_recv += len;
        remaining_len -= len;
    }

    return total_recv;
}

[残りは演習として残します。]

コードとの主な違いは、メイン ループがはるかに単純であることです。複数のaccept呼び出し (なぜ必要なのですか?) や、いくつかの異なる読み取り関数と書き込み関数は必要ありません。関数のように、コードの一部をさらに単純化することができますrecv_all

また、上記のコードは一度に 1 つの接続しか処理しないことに注意してください。これを解決する 1 つの方法は、着信接続ごとに新しいスレッドを作成するか、接続とバッファーのリストを使用してより高度な方法を使用し、selectそれらとリッスン ソケットの間で多重化することです。

于 2012-04-04T11:50:41.037 に答える