টিসিপি স্থানীয় সকেটের ঠিকানাটি কতক্ষণ বন্ধ থাকার পরে অনুপলব্ধ হয়ে আবদ্ধ?


13

লিনাক্সে (আমার লাইভ সার্ভারগুলি RHEL 5.5 এ রয়েছে - নীচের LXR লিঙ্কগুলি সেই কার্নেলের সংস্করণে রয়েছে), man 7 ipবলেছেন:

একটি টিসিপি স্থানীয় সকেট ঠিকানা যা আবদ্ধ হয়েছে তা বন্ধ হওয়ার পরে কিছু সময়ের জন্য অনুপলব্ধ, যদি না SO_REUSEADDR পতাকা সেট করা থাকে।

আমি ব্যবহার করছি না SO_REUSEADDR। "কিছু সময়" কত দিন? আমি এটি জানতে পারি কীভাবে এটি দীর্ঘ হয় এবং আমি কীভাবে এটি পরিবর্তন করতে পারি?

আমি এটিকে ঘিরে গুগল করছি এবং কয়েকটি সংখ্যক তথ্য পেয়েছি, যার মধ্যে একটিও সত্যই কোনও অ্যাপ্লিকেশন প্রোগ্রামারের দৃষ্টিকোণ থেকে এটি ব্যাখ্যা করে না। বুদ্ধিমান:

  • TCP_TIMEWAIT_LEN ইন net/tcp.h"TIME-WAIT রাজ্যটি ধ্বংস করতে কতক্ষণ অপেক্ষা করতে হবে", এবং "প্রায় 60 সেকেন্ড" এ স্থির করা হয়েছে
  • / proc / sys / নেট / ipv4 / tcp_fin_Toutout "রাষ্ট্র FIN-WAIT-2 এ সকেট ধরে রাখার সময়, যদি এটি আমাদের পাশ দিয়ে বন্ধ করা হত", এবং "ডিফল্ট মান 60 সেকেন্ড"

যেখানে আমি হোঁচট খাচ্ছি সেখানে টিসিপি লাইফাইসাইকেলের কার্নেলের মডেল এবং প্রোগ্রামারগুলির বন্দরগুলির মডেলটি অনুপলব্ধ হওয়ার মধ্যবর্তী ব্যবধানটি কমিয়ে দিচ্ছে, অর্থাত্ এই রাজ্যগুলি "কিছু সময়ের" সাথে কীভাবে সম্পর্কিত understanding


@ কালেব: ট্যাগ সম্পর্কিত, বাঁধাই একটি সিস্টেম কলও! man 2 bindআপনি আমাকে বিশ্বাস না হলে চেষ্টা করুন । স্বীকার করা যায় যে, ইউনিক্স যখন কেউ "বাঁধাই" বলে যথেষ্ট পরিমাণে যথেষ্ট বলে এটি সম্ভবত প্রথম বিষয় নয়।
টম অ্যান্ডারসন

বিকল্পগুলির ব্যবহারগুলি সম্পর্কে আমি ভালভাবে অবগত ছিলাম bindতবে এখানে ট্যাগটি বিশেষত ডিএনএস সার্ভারে প্রয়োগ করা হয়। আমাদের কাছে প্রতিটি সম্ভাব্য সিস্টেম কলের জন্য ট্যাগ নেই।
কালেব

উত্তর:


14

আমি বিশ্বাস করি যে কোনও প্রোগ্রামে সকেটের অনুপলব্ধ ধারণাটি হ'ল ট্রানজিটে থাকা কোনও টিসিপি ডেটা বিভাগকে পৌঁছানোর অনুমতি দেওয়া এবং কার্নেল দ্বারা ফেলে দেওয়া। এটি হ'ল, কোনও অ্যাপ্লিকেশনটির জন্য close(2)কোনও সকেটে কল করা সম্ভব , তবে প্যাকেটগুলি নিয়ন্ত্রণ করতে বিলম্ব বা দুর্ঘটনাগুলি ঘুরিয়ে দেওয়া বা আপনার কাছে টিসিপি সংযোগের অন্য দিকটি কিছুক্ষণের জন্য ডেটা প্রেরণের অনুমতি দিতে পারে। অ্যাপ্লিকেশনটি ইঙ্গিত করেছে যে এটি আর টিসিপি ডেটা বিভাগগুলির সাথে আর কোনও व्यवहार করতে চায় না, তাই কার্নেলটি কেবল তাদের আসার সাথে সাথে এগুলি ফেলে দেওয়া উচিত।

আমি সি তে একটি সামান্য প্রোগ্রাম হ্যাক করেছি যা আপনি সংকলন করতে এবং টাইমআউটটি কত দীর্ঘ তা দেখতে ব্যবহার করতে পারেন:

#include <stdio.h>        /* fprintf() */
#include <string.h>       /* strerror() */
#include <errno.h>        /* errno */
#include <stdlib.h>       /* strtol() */
#include <signal.h>       /* signal() */
#include <sys/time.h>     /* struct timeval */
#include <unistd.h>       /* read(), write(), close(), gettimeofday() */
#include <sys/types.h>    /* socket() */
#include <sys/socket.h>   /* socket-related stuff */
#include <netinet/in.h>
#include <arpa/inet.h>    /* inet_ntoa() */
float elapsed_time(struct timeval before, struct timeval after);
int
main(int ac, char **av)
{
        int opt;
        int listen_fd = -1;
        unsigned short port = 0;
        struct sockaddr_in  serv_addr;
        struct timeval before_bind;
        struct timeval after_bind;

        while (-1 != (opt = getopt(ac, av, "p:"))) {
                switch (opt) {
                case 'p':
                        port = (unsigned short)atoi(optarg);
                        break;
                }
        }

        if (0 == port) {
                fprintf(stderr, "Need a port to listen on\n");
                return 2;
        }

        if (0 > (listen_fd = socket(AF_INET, SOCK_STREAM, 0))) {
                fprintf(stderr, "Opening socket: %s\n", strerror(errno));
                return 1;
        }

        memset(&serv_addr, '\0', sizeof(serv_addr));
        serv_addr.sin_family      = AF_INET;
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        serv_addr.sin_port        = htons(port);

        gettimeofday(&before_bind, NULL);
        while (0 > bind(listen_fd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))) {
                fprintf(stderr, "binding socket to port %d: %s\n",
                        ntohs(serv_addr.sin_port),
                        strerror(errno));

                sleep(1);
        }
        gettimeofday(&after_bind, NULL);
        printf("bind took %.5f seconds\n", elapsed_time(before_bind, after_bind));

        printf("# Listening on port %d\n", ntohs(serv_addr.sin_port));
        if (0 > listen(listen_fd, 100)) {
                fprintf(stderr, "listen() on fd %d: %s\n",
                        listen_fd,
                        strerror(errno));
                return 1;
        }

        {
                struct sockaddr_in  cli_addr;
                struct timeval before;
                int newfd;
                socklen_t clilen;

                clilen = sizeof(cli_addr);

                if (0 > (newfd = accept(listen_fd, (struct sockaddr *)&cli_addr, &clilen))) {
                        fprintf(stderr, "accept() on fd %d: %s\n", listen_fd, strerror(errno));
                        exit(2);
                }
                gettimeofday(&before, NULL);
                printf("At %ld.%06ld\tconnected to: %s\n",
                        before.tv_sec, before.tv_usec,
                        inet_ntoa(cli_addr.sin_addr)
                );
                fflush(stdout);

                while (close(newfd) == EINTR) ;
        }

        if (0 > close(listen_fd))
                fprintf(stderr, "Closing socket: %s\n", strerror(errno));

        return 0;
}
float
elapsed_time(struct timeval before, struct timeval after)
{
        float r = 0.0;

        if (before.tv_usec > after.tv_usec) {
                after.tv_usec += 1000000;
                --after.tv_sec;
        }

        r = (float)(after.tv_sec - before.tv_sec)
                + (1.0E-6)*(float)(after.tv_usec - before.tv_usec);

        return r;
}

আমি এই প্রোগ্রামটি 3 টি বিভিন্ন মেশিনে চেষ্টা করেছি এবং 55 থেকে 59 সেকেন্ডের মধ্যে যখন কার্নেল অ-রুট ব্যবহারকারীকে সকেটটি পুনরায় খোলার অনুমতি দিতে অস্বীকার করে তখন আমি একটি পরিবর্তনশীল সময় পাই। আমি উপরের কোডটি "ওপেনার" নামক একটি এক্সিকিউটেবলের কাছে সংকলিত করেছি এবং এটিকে এভাবে চালিয়েছি:

./opener -p 7896; ./opener -p 7896

আমি অন্য উইন্ডোটি খুললাম এবং এটি করেছি:

telnet otherhost 7896

এর ফলে "ওপেনার" এর প্রথম উদাহরণটি কোনও সংযোগ গ্রহণ করে, তারপরে এটি বন্ধ করে দেয়। "ওপেনার" এর দ্বিতীয় উদাহরণটি bind(2)প্রতি সেকেন্ডে টিসিপি পোর্টে 7896 চেষ্টা করে। "ওপেনার" 55 থেকে 59 সেকেন্ড বিলম্বের কথা জানায়।

চারপাশে গুগল করে, আমি দেখতে পাচ্ছি যে লোকেরা এটি করার পরামর্শ দেয়:

echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout

যে অন্তর কমাতে। এটি আমার পক্ষে কাজ করে না। 4 টি লিনাক্স মেশিনে আমার অ্যাক্সেস ছিল, দুটিতে 30 এবং দুটিতে 60 টি ছিল I আমি সেই মানটি 10 ​​হিসাবেও কম সেট করেছিলাম "" ওপেনার "প্রোগ্রামের সাথে কোনও পার্থক্য নেই।

এটা করছি:

echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle

জিনিস পরিবর্তন করেছেন। দ্বিতীয় "ওপেনার" এটির নতুন সকেট পেতে মাত্র 3 সেকেন্ড সময় নিয়েছিল।


3
আমি উপলব্ধি (মোটামুটিভাবে) অপ্রাপ্যতার সময়কালের উদ্দেশ্য কি। আমি যেটি জানতে চাই তা হ'ল লিনাক্সে সেই সময়কালটি ঠিক কত দিন, এবং কীভাবে এটি পরিবর্তন করা যায়। টিসিপি সম্পর্কে উইকিপিডিয়া পৃষ্ঠা থেকে একটি সংখ্যার সমস্যা হ'ল এটি অবশ্যই একটি সাধারণ মানের, এবং আমার নির্দিষ্ট প্ল্যাটফর্মের সাথে অবশ্যই সত্য যে এমন কিছু নয়।
টম অ্যান্ডারসন

আপনার জল্পনা আকর্ষণীয় ছিল! এগুলি মুছে ফেলার পরিবর্তে কেবল তাদের শিরোনাম হিসাবে চিহ্নিত করুন, এটি কারণ অনুসন্ধানের জন্য উপায় দেয়!
ফিলিপ গ্যাচাউড
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.