সকেট সংযোগ () বনাম বাঁধাই ()


121

উভয় connect()এবং bind()সিস্টেম একটি ঠিকানায় 'সহযোগী' সকেট ফাইল বিবরণকারীকে কল করে (সাধারণত একটি আইপি / পোর্ট সংমিশ্রণ)। তাদের প্রোটোটাইপগুলি হ'ল: -

int connect(int sockfd, const struct sockaddr *addr,
               socklen_t addrlen);

এবং

int bind(int sockfd, const struct sockaddr *addr,
            socklen_t addrlen);

2 টি কল মধ্যে সঠিক পার্থক্য কি? যখন ব্যবহার করা উচিত connect()এবং কখন bind()?

বিশেষত, কিছু নমুনা সার্ভার ক্লায়েন্ট কোডগুলিতে, পাওয়া গেছে যে ক্লায়েন্ট ব্যবহার করছে connect()এবং সার্ভার bind()কলটি ব্যবহার করছে । কারণ আমার কাছে পুরোপুরি পরিষ্কার ছিল না।


19
এক বাক্যে: বাইন্ডটি স্থানীয় ঠিকানায়, সংযোগটি দূরবর্তী ঠিকানায়।
SHR

উত্তর:


230

বোঝাপড়াটি আরও ভাল করার জন্য, ছবিতে ঠিক কোথায় বাঁধাই এবং সংযোগ আসে তা সন্ধান করি,

সৌরভ দ্বারা স্পষ্ট হিসাবে দুটি কলের অবস্থানের জন্য,

বাইন্ড () সকেটটিকে তার স্থানীয় ঠিকানার সাথে সংযুক্ত করে [সে কারণেই সার্ভারের সাইডটি বাঁধাই করে, যাতে ক্লায়েন্টরা সেই ঠিকানাটি সার্ভারের সাথে সংযোগ করার জন্য ব্যবহার করতে পারে]] সংযোগ () একটি দূরবর্তী [সার্ভার] ঠিকানার সাথে সংযোগ করতে ব্যবহৃত হয়, এজন্য ক্লায়েন্টের পক্ষ রয়েছে , সংযুক্ত [যেমন পড়ুন: সার্ভারে সংযুক্ত করুন] ব্যবহৃত হয়।

নির্দিষ্ট ভূমিকা ও সংশ্লিষ্ট বাস্তবায়নের কারণে আমরা এগুলি আন্তঃআযোগযোগ্যভাবে ব্যবহার করতে পারি না (একই মেশিনে আমাদের ক্লায়েন্ট / সার্ভার থাকা অবস্থায়ও)।

আমি আরও এই কলগুলি টিসিপি / আইপি হ্যান্ডশেকের সাথে সম্পর্কিত করার পরামর্শ দেব।

এখানে চিত্র বর্ণনা লিখুন

সুতরাং, কে এখানে এসওয়াইএন পাঠাবে, এটি সংযুক্ত হবে ()। যদিও বাইন্ড () যোগাযোগের শেষ পয়েন্টটি সংজ্ঞায়িত করার জন্য ব্যবহৃত হয়।

আশাকরি এটা সাহায্য করবে!!


1
ধন্যবাদ ভাই. ডায়াগ্রামের সাহায্যে সবকিছু দ্রুত আনস্ট্যান্ড করতে পারে। আপনি কি এখানে পার্থক্য বলতে পারেন, যদি আমরা ইউডিপি ব্যবহার করি?
এপিএম

8
গ্রাহক
tschodt

আমি মনে করি পি 2 পি নেটওয়ার্কের নেটওয়ার্কের সমস্ত নোডের বাইন্ড ব্যবহার করা উচিত, আমি কি সঠিক?
ক্যাপিল

46

এক লাইনার: bind() নিজের ঠিকানা, connect()দূরবর্তী ঠিকানার কাছে।

ম্যান পৃষ্ঠা থেকে উদ্ধৃতি bind()

বাইন্ড () ফাইল বিবরণকারী সকফডি দ্বারা উল্লিখিত সকেটে অ্যাডারের দ্বারা নির্দিষ্ট ঠিকানা নির্ধারণ করে। অ্যাড্রলেন অ্যাড্রেস দ্বারা নির্দেশিত ঠিকানা কাঠামোর আকার, বাইটে নির্দিষ্ট করে। Ditionতিহ্যগতভাবে, এই অপারেশনটিকে "সকেটে একটি নাম নির্ধারণ করা" বলা হয়।

এবং, একই থেকে connect()

কানেক্ট () সিস্টেম কলটি অ্যাড্রেয়ারের দ্বারা নির্দিষ্ট করা ঠিকানায় ফাইল বর্ণনাকারী সকফডি দ্বারা উল্লিখিত সকেটকে সংযুক্ত করে।

স্পষ্ট করা,

  • bind()সকেটটিকে তার স্থানীয় ঠিকানার সাথে সংযুক্ত করে [সে কারণেই সার্ভার সাইড bindএস, যাতে ক্লায়েন্টরা সেই ঠিকানাটি সার্ভারের সাথে সংযোগ স্থাপন করতে পারে]]
  • connect() একটি দূরবর্তী [সার্ভার] ঠিকানার সাথে সংযোগ করতে ব্যবহৃত হয়, এজন্য ক্লায়েন্ট সাইড, সংযুক্ত [হিসাবে পড়ুন: সার্ভারে সংযুক্ত করুন] ব্যবহৃত হয়।

সুতরাং, বলুন, সার্ভার এবং ক্লায়েন্ট উভয় প্রক্রিয়া যদি একই মেশিনে চালিত হয় তবে সেগুলি কি বিনিময়যোগ্যভাবে ব্যবহার করা যেতে পারে?
সিদ্ধার্থ ঘোষ

1
@SiddharthaGhosh নং হয়তো ক্লায়েন্ট এবং সার্ভার একই মেশিনে হয়, কিন্তু এখনও তারা হয় ডান বিভিন্ন প্রক্রিয়া? উভয়ই এপিআই তার নিজস্ব puprpose পরিবেশন করে। তারা কখনই নয়interchangeable
সৌরভ ঘোষ

এই প্রসঙ্গে স্থানীয় এবং দূরবর্তী দ্বারা ঠিক কী বোঝানো হয়েছে?
সিদ্ধার্থ ঘোষ

@ সিদ্ধার্থঘোষ local-> প্রক্রিয়াটি নিজেই remote-> অন্যান্য প্রক্রিয়া।
সৌরভ ঘোষ

@ সৌরভঘোষ তাই এর অর্থ আমি ক্লায়েন্টের সাথে বাঁধতে কোনও বন্দর নির্দিষ্ট করতে পারি না?
হেনগি চেন

12

বাইন্ড চলমান প্রক্রিয়াটিকে একটি বন্দর দাবি করতে বলে। উদাহরণস্বরূপ, এটি 80 পোর্টে নিজেকে বেঁধে রাখা উচিত এবং অজানা অনুরোধগুলি শুনতে হবে। বাঁধাইয়ের সাথে, আপনার প্রক্রিয়াটি একটি সার্ভারে পরিণত হয়। আপনি যখন কানেক্ট ব্যবহার করেন, আপনি আপনার প্রক্রিয়াটি এমন কোনও বন্দরের সাথে সংযোগ স্থাপনের জন্য বলুন যা আগেই ব্যবহৃত হয়। আপনার প্রক্রিয়া ক্লায়েন্ট হয়ে যায়। পার্থক্যটি গুরুত্বপূর্ণ: বাঁধাই এমন একটি পোর্ট চায় যা ব্যবহারে নেই (যাতে এটি দাবি করে সার্ভারে পরিণত হতে পারে), এবং সংযোগটি এমন একটি পোর্ট চায় যা ইতিমধ্যে ব্যবহৃত (যাতে এটি এর সাথে সংযোগ স্থাপন করে এবং সার্ভারের সাথে কথা বলতে পারে)


9

উইকিপিডিয়া থেকে http://en.wikedia.org/wiki/Berkeley_sockets#bind.28.29

সংযোগ ():

সংযোগ () সিস্টেম কলটি আর্গুমেন্ট তালিকার সেই হোস্টের ঠিকানা দ্বারা নির্দিষ্ট একটি দূরবর্তী হোস্টের সাথে তার ফাইল বর্ণনাকারী দ্বারা চিহ্নিত একটি সকেটকে সংযুক্ত করে।

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

সংযুক্ত () ত্রুটি কোড উপস্থাপন করে একটি পূর্ণসংখ্যা ফেরত দেয়: 0 সাফল্যের প্রতিনিধিত্ব করে, যখন -1 একটি ত্রুটি উপস্থাপন করে।

বাঁধাই করা():

বাইন্ড () কোনও ঠিকানায় একটি সকেট বরাদ্দ করে। সকেট () ব্যবহার করে কোনও সকেট তৈরি করা হলে, এটি কেবলমাত্র একটি প্রোটোকল পরিবার দেওয়া হয়, তবে কোনও ঠিকানা বরাদ্দ করা হয় না। সকেট অন্যান্য হোস্টের সাথে সংযোগ গ্রহণ করার আগে কোনও ঠিকানার সাথে এই সংস্থানটি বাইন্ড () সিস্টেম কল সহ সম্পাদন করতে হবে। বাইন্ড () তিনটি আর্গুমেন্ট নেয়:

সোকফডি, বাইন্ড অন সম্পাদন করতে সকেটের প্রতিনিধিত্বকারী একটি বর্ণনাকারী। আমার_এডিডিআর, একটি সোকাড্ড্রির কাঠামোর পয়েন্টার যা ঠিকানার সাথে আবদ্ধ হওয়ার জন্য প্রতিনিধিত্ব করে। অ্যাডরলেন, একটি সোকলেন_t ক্ষেত্র যা সোকাড্ডার কাঠামোর আকার নির্দিষ্ট করে। বাঁধাই () সাফল্যে 0-এবং কোনও ত্রুটি দেখা দিলে -1 প্রদান করে।

উদাহরণ: 1.) কানেক্ট ব্যবহার করে

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>

int main(){
  int clientSocket;
  char buffer[1024];
  struct sockaddr_in serverAddr;
  socklen_t addr_size;

  /*---- Create the socket. The three arguments are: ----*/
  /* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
  clientSocket = socket(PF_INET, SOCK_STREAM, 0);

  /*---- Configure settings of the server address struct ----*/
  /* Address family = Internet */
  serverAddr.sin_family = AF_INET;
  /* Set port number, using htons function to use proper byte order */
  serverAddr.sin_port = htons(7891);
  /* Set the IP address to desired host to connect to */
  serverAddr.sin_addr.s_addr = inet_addr("192.168.1.17");
  /* Set all bits of the padding field to 0 */
  memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);  

  /*---- Connect the socket to the server using the address struct ----*/
  addr_size = sizeof serverAddr;
  connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);

  /*---- Read the message from the server into the buffer ----*/
  recv(clientSocket, buffer, 1024, 0);

  /*---- Print the received message ----*/
  printf("Data received: %s",buffer);   

  return 0;
}

2.) বাইন্ড উদাহরণ:

int main()
{
    struct sockaddr_in source, destination = {};  //two sockets declared as previously
    int sock = 0;
    int datalen = 0;
    int pkt = 0;

    uint8_t *send_buffer, *recv_buffer;

    struct sockaddr_storage fromAddr;   // same as the previous entity struct sockaddr_storage serverStorage;
    unsigned int addrlen;  //in the previous example socklen_t addr_size;
    struct timeval tv;
    tv.tv_sec = 3;  /* 3 Seconds Time-out */
    tv.tv_usec = 0;

    /* creating the socket */         
    if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) 
        printf("Failed to create socket\n");

    /*set the socket options*/
    setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(struct timeval));

    /*Inititalize source to zero*/
    memset(&source, 0, sizeof(source));       //source is an instance of sockaddr_in. Initialization to zero
    /*Inititalize destinaton to zero*/
    memset(&destination, 0, sizeof(destination));


    /*---- Configure settings of the source address struct, WHERE THE PACKET IS COMING FROM ----*/
    /* Address family = Internet */
    source.sin_family = AF_INET;    
    /* Set IP address to localhost */   
    source.sin_addr.s_addr = INADDR_ANY;  //INADDR_ANY = 0.0.0.0
    /* Set port number, using htons function to use proper byte order */
    source.sin_port = htons(7005); 
    /* Set all bits of the padding field to 0 */
    memset(source.sin_zero, '\0', sizeof source.sin_zero); //optional


    /*bind socket to the source WHERE THE PACKET IS COMING FROM*/
    if (bind(sock, (struct sockaddr *) &source, sizeof(source)) < 0) 
        printf("Failed to bind socket");

    /* setting the destination, i.e our OWN IP ADDRESS AND PORT */
    destination.sin_family = AF_INET;                 
    destination.sin_addr.s_addr = inet_addr("127.0.0.1");  
    destination.sin_port = htons(7005); 

    //Creating a Buffer;
    send_buffer=(uint8_t *) malloc(350);
    recv_buffer=(uint8_t *) malloc(250);

    addrlen=sizeof(fromAddr);

    memset((void *) recv_buffer, 0, 250);
    memset((void *) send_buffer, 0, 350);

    sendto(sock, send_buffer, 20, 0,(struct sockaddr *) &destination, sizeof(destination));

    pkt=recvfrom(sock, recv_buffer, 98,0,(struct sockaddr *)&destination, &addrlen);
    if(pkt > 0)
        printf("%u bytes received\n", pkt);
    }

আমি আশা করি যে পার্থক্য স্পষ্ট করে

দয়া করে নোট করুন যে আপনি যে সকেট প্রকারটি ঘোষণা করেছেন তা আপনার প্রয়োজনীয়তার উপর নির্ভর করবে, এটি অত্যন্ত গুরুত্বপূর্ণ


9

আমার মনে হয় এটা আপনার ধী সাহায্য করবে যদি আপনি মনে connect()এবং listen()বদলে প্রতিরূপ হিসেবে connect()এবং bind()। এর কারণ হ'ল আপনি bind()আগে কল করতে বা বাদ দিতে পারেন, যদিও এটি আগে কল করা বা আগে কল করা ভাল connect()নয় listen()

যদি এটি সার্ভার এবং ক্লায়েন্টগুলির বিবেচনায় চিন্তা করতে সহায়তা করে তবে এটি হ'ল listen()এটি পূর্বের এবং connect()পরেরগুলির বৈশিষ্ট্য।bind()পাওয়া যাবে - না পাওয়া - উভয়ই পাওয়া যায়।

যদি আমরা ধরে নিই যে আমাদের সার্ভার এবং ক্লায়েন্ট বিভিন্ন মেশিনে রয়েছে, তবে বিভিন্ন ফাংশনগুলি বোঝা সহজ হয়ে যায়।

bind()স্থানীয়ভাবে কাজ করে, যার অর্থ এটি অনুরোধ করা ঠিকানায়, যাকে বলা হয় সেই মেশিনের সংযোগের শেষটি আবদ্ধ করে এবং আপনাকে অনুরোধ করা বন্দরটি বরাদ্দ করে। এটি যে মেশিনটি ক্লায়েন্ট বা সার্ভার হবে তা নির্বিশেষে এটি করে। connect()কোনও সার্ভারের সাথে একটি সংযোগ সূচনা করে, যার অর্থ এটি কোনও ক্লায়েন্টের কাছ থেকে সার্ভারের অনুরোধ করা ঠিকানা এবং পোর্টের সাথে সংযোগ স্থাপন করে। সেই সার্ভারটি অবশ্যই অবশ্যই bind()পূর্বে কল করেছে listen(), যাতে আপনি কোন ঠিকানা এবং পোর্ট ব্যবহার করে এর সাথে সংযোগ স্থাপন করতে পারবেন তা জানতে সক্ষম হতেconnect()

আপনি যদি কল না করেন bind(), কোনও পোর্ট এবং ঠিকানা স্পষ্টভাবে নির্ধারিত হবে এবং স্থানীয় মেশিনে আবদ্ধ হবে যখন আপনি কোনও connect()(ক্লায়েন্ট) বা কল করবেনlisten() (সার্ভার) । তবে এটি উভয়েরই পার্শ্ব প্রতিক্রিয়া, তাদের উদ্দেশ্য নয়। এই পদ্ধতিতে নির্ধারিত একটি বন্দরটি সাময়িক কালীন।

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

আমি ধরে নিলাম যেমন আপনি উল্লেখ করেছেন যে আপনি টিসিপিতে connect()আগ্রহী, কিন্তু এটি ইউডিপিকেও বহন করে, যেখানে bind()প্রথমটির আগে কল না করা sendto()(ইউডিপি সংযোগ-কম) এছাড়াও একটি বন্দর এবং ঠিকানা সুস্পষ্টভাবে নির্ধারিত এবং আবদ্ধ হতে বাধ্য করে। বাঁধাই ব্যতীত আপনি যে ফাংশনটি কল করতে পারবেন না তা হ'ল এটি recvfrom()একটি ত্রুটি ফিরিয়ে দেবে, কারণ একটি নির্ধারিত বন্দর এবং আবদ্ধ ঠিকানা ব্যতীত, (বা খুব বেশি পরিমাণে, আপনি কোনও বাইন্ডিংয়ের অনুপস্থিতি কীভাবে ব্যাখ্যা করেন তার উপর নির্ভর করে) প্রাপ্তির কিছুই নেই।


1

অনেক দেরি; পড়ুন না: পার্থক্যটি হ'ল উত্স (স্থানীয়) বা গন্তব্য ঠিকানা / পোর্ট সেট করা হচ্ছে কিনা। সংক্ষেপে, bind()উত্সটি connect()সেট করুন এবং গন্তব্য সেট করুন। টিসিপি বা ইউডিপি নির্বিশেষে।

bind()

bind()সকেটের স্থানীয় (উত্স) ঠিকানা সেট করুন। এই ঠিকানাটি যেখানে প্যাকেট প্রাপ্ত হয়। সকেট দ্বারা প্রেরিত প্যাকেটগুলি এটি উত্সের ঠিকানা হিসাবে বহন করে, তাই অন্য হোস্টরা জানতে পারে এর প্যাকেটগুলি কোথায় পাঠাতে হবে।

যদি প্রাপ্তির প্রয়োজন হয় না তবে সকেটের উত্সের ঠিকানাটি অকেজো। টিসিপির মতো প্রোটোকলগুলির সঠিকভাবে প্রেরণের জন্য সক্ষম হওয়া দরকার, কারণ এক বা একাধিক প্যাকেট উপস্থিত হওয়ার পরে গন্তব্য হোস্ট একটি নিশ্চিতকরণ ফেরত পাঠায় (অর্থাত স্বীকৃতি)।

connect()

  • টিসিপির একটি "সংযুক্ত" অবস্থা রয়েছে। connect()অন্যদিকে সংযোগ স্থাপনের চেষ্টা করার জন্য টিসিপি কোডটিকে ট্রিগার করে।
  • ইউডিপির কোনও "সংযুক্ত" অবস্থা নেই। connect()কোনও ডিফল্ট ঠিকানা সেট করুন যেখানে কোনও ঠিকানা সুনির্দিষ্ট না করা হলে প্যাকেটগুলি পাঠানো হয়। কখন connect()ব্যবহৃত হয় না, sendto()বা sendmsg()অবশ্যই গন্তব্য ঠিকানা যুক্ত ব্যবহার করা উচিত।

যখন connect()বা একটি প্রেরণ ফাংশন বলা হয়, এবং কোনও ঠিকানা আবদ্ধ হয় না, লিনাক্স স্বয়ংক্রিয়ভাবে সকেটটিকে একটি এলোমেলো বন্দরে আবদ্ধ করে। প্রযুক্তিগত বিশদগুলির জন্য, inet_autobind()লিনাক্স কার্নেল উত্স কোডটি একবার দেখুন।

পার্শ্ব নোট

  • listen() কেবলমাত্র টিসিপি।
  • ইন AF_INET পরিবার, সকেট এর উৎস বা গন্তব্য ঠিকানা ( struct sockaddr_in) IP ঠিকানা দ্বারা স্থিরীকৃত হয় (দেখুন আইপি হেডার ), এবং বিভিন্ন TCP অথবা UDP পোর্ট (দেখতে বিভিন্ন TCP এবং এর ফলে UDP হেডার)।
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.