الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

سؤال في Sockets في لغة C

مغلقمُجاب
بدأه farid777 في 11 ديسمبر 2013 · 3 رد · 1,222 مشاهدة · في الأسئلة المجابة
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

post-25052-1275926239911.gif

والسلام عليكم والصلاة والسلام على اشرف النبيين والرسل سيدنا محمد.....

مرحبا اخوتي الكرام :)

اردت ان اشارك هذا الكود معكم للاستفادة 
وايضا يوجد لدي بعض الاسئلة لاهل الخبرة

----------------------------------------

اني افهم تقريبا كل شيء من هذا الكود فقط لقطة صغيرة غير مفهومة وارجو شرحها

------------------------------------------------

bzero(&(server_addr.sin_zero),8);

if (bind(sock,(struct sockaddr *)&server_addr,sizeof(struct sockaddr)==-1)) {
perror("Unable to bind");
exit(1);
}

----------------------------------------

ما الحاجة من ال - bzero وال sizeof(struct sockaddr)
وماذا يعني * struct sockaddr

----------------------------------------

tcpserver.c

/* tcpserver.c */

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>


int main()
{
        int sock, connected, bytes_recieved , true = 1;  
        char send_data [1024] , recv_data[1024];       

        struct sockaddr_in server_addr,client_addr;    
        int sin_size;
        
        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            perror("Socket");
            exit(1);
        }

        if (setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&true,sizeof(int)) == -1) {
            perror("Setsockopt");
            exit(1);
        }
        
        server_addr.sin_family = AF_INET;         
        server_addr.sin_port = htons(5000);     
        server_addr.sin_addr.s_addr = INADDR_ANY; 
        bzero(&(server_addr.sin_zero),8); 

        if (bind(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))
                                                                       == -1) {
            perror("Unable to bind");
            exit(1);
        }

        if (listen(sock, 5) == -1) {
            perror("Listen");
            exit(1);
        }
		
	printf("\nTCPServer Waiting for client on port 5000");
        fflush(stdout);


        while(1)
        {  

            sin_size = sizeof(struct sockaddr_in);

            connected = accept(sock, (struct sockaddr *)&client_addr,&sin_size);

            printf("\n I got a connection from (%s , %d)",
                   inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));

            while (1)
            {
              printf("\n SEND (q or Q to quit) : ");
              gets(send_data);
              
              if (strcmp(send_data , "q") == 0 || strcmp(send_data , "Q") == 0)
              {
                send(connected, send_data,strlen(send_data), 0); 
                close(connected);
                break;
              }
               
              else
                 send(connected, send_data,strlen(send_data), 0);  

              bytes_recieved = recv(connected,recv_data,1024,0);

              recv_data[bytes_recieved] = '\0';

              if (strcmp(recv_data , "q") == 0 || strcmp(recv_data , "Q") == 0)
              {
                close(connected);
                break;
              }

              else 
              printf("\n RECIEVED DATA = %s " , recv_data);
              fflush(stdout);
            }
        }       

      close(sock);
      return 0;
}

tcpclient.c

/* tcpclient.c */

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>


int main()

{

        int sock, bytes_recieved;  
        char send_data[1024],recv_data[1024];
        struct hostent *host;
        struct sockaddr_in server_addr;  

        host = gethostbyname("127.0.0.1");

        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
            perror("Socket");
            exit(1);
        }

        server_addr.sin_family = AF_INET;     
        server_addr.sin_port = htons(5000);   
        server_addr.sin_addr = *((struct in_addr *)host->h_addr);
        bzero(&(server_addr.sin_zero),8); 

        if (connect(sock, (struct sockaddr *)&server_addr,
                    sizeof(struct sockaddr)) == -1) 
        {
            perror("Connect");
            exit(1);
        }

        while(1)
        {
        
          bytes_recieved=recv(sock,recv_data,1024,0);
          recv_data[bytes_recieved] = '\0';
 
          if (strcmp(recv_data , "q") == 0 || strcmp(recv_data , "Q") == 0)
          {
           close(sock);
           break;
          }

          else
           printf("\nRecieved data = %s " , recv_data);
           
           printf("\nSEND (q or Q to quit) : ");
           gets(send_data);
           
          if (strcmp(send_data , "q") != 0 && strcmp(send_data , "Q") != 0)
           send(sock,send_data,strlen(send_data), 0); 

          else
          {
           send(sock,send_data,strlen(send_data), 0);   
           close(sock);
           break;
          }
        
        }   
return 0;
}

ارجو المساعدة والسلام عليكم والصلاة والسلام على اشرف النبيين والرسل سيدنا محمد.....

تم تعديل هذه المشاركة بواسطة مصطفى 36a2 في 11 ديسمبر 2013 في 15:44 — السبب: تنسيق الكود و الروابط

#2 أفضل إجابة

السلام عليكم ..

الـــ POSIX  تسمح لنا بالتعامل مع عدة أنواع من بروتوكولات في الاتصال  , و لكل نوع له struct  خاص به يحوي المتحولات و العناوين المطلوبة للبروتوكول (يمثل endpoint), و لكي لا يتم تعريف دوال accept  و bind  لكل نوع من البروتوكولات , تم تعريف نوع عام اسمه (struct sockaddr) لنقل أنه يمثل بروتوكول عام   .... لاحظ  أن الدوال التالية: 

int accept(struct socket *s, struct sockaddr *addr, int *addrlen, struct socket **retval)
int bind(int socket, const struct sockaddr *address, socklen_t address_len);

 كلها فيها بارمتر من نوع  (struct sockaddr) ..

الآن ما هو الــ (struct sockaddr) : 

struct sockaddr {
    unsigned short    sa_family;    // address family, AF_xxx
    char              sa_data[14];  // 14 bytes of protocol address
};

لاحظ ان حجمه هو 2 + 14  = 16 بايت ..

الآن لإنشاء internet socket  (IPV4)  تحتاج لمتحولات مختلفة لتمثيل بيانات الــ Enfpoint  و التي يمثلها الـــ  (struct sockaddr_in): 

أما IPV6  يمثله  (sockaddr_in6)

struct sockaddr_in {
    short            sin_family;   // e.g. AF_INET, AF_INET6
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // see struct in_addr, below
    char             sin_zero[8];  // zero this if you want to
};

حيث :

struct in_addr {    unsigned long s_addr;       };

 (لاحظ لدينا port مثلا ) ... الآن  لاحظ ان حجم الــ sockaddr_in  دون  (sin_zero) هو فقط 8 بايت , لذلك تم إضافة هذه الــ 8 بايت كحشوة له كي يصبح حجمه 16 بايت حتى لا تحصل مشاكل في أحجام الذاكرة لان الدوال السابقة تأخذ البارمترات من نوع (sockaddr) الذي حجمه كما قلنا 16 بايت .. 

مراجع اخرى تقول : 

اقتباس

 

The POSIX specification requires only three members in the structure: sin_family, sin_addr, and sin_port. It is acceptable for a POSIX-compliant implementation to define additional structure members, and this is normal for an Internet socket address structure. Almost all implementations add the sin_zero member so that all socket address structures are at least 16 bytes in size

 

أي أن كل الــ Structs   الخاصة بعناوين السوكيت يجب أن تكون 16 بايت كجد ادنى , لذلك تم أضافة حشوة للــ (struct sockaddr_in) .

جرت العادة ان هذا المتحول  الحشوة (sin_zero) يتم ملؤه  بالقيم الفارغة  عن طريق bzero  أو memset  للمتحول sockaddr_in  و حتى لا يحوي قيم عشوائية من الذاكرة مثل (H↑a) .. مثلا :

struct sockaddr_in serversin;
memset(&serversin, 0, sizeof(serversin));

حسب الــ MSDN  (رابط)  يكون : 

اقتباس

sin_zero

Padding to make structure the same size as SOCKADDR.

بالعودة لسؤالك عن :  sizeof(struct sockaddr) الذي يعطي حجم الــ struct  أي 16   :

 

تم تعريف عدة  structs  يمكن استخدامها في تحديد البروتوكول و هي .

  , sockaddr_in , sockaddr_in6 , sockaddr_un  ... الخ .. و كلها يمكن تمريرها للدالة bind  ...التي تاخذ وسيط من نوع  struct sockaddr , و لكن هذه الدالة كيف ستعرف أن المتحول الممرر هو sockaddr_in أو sockaddr_in6 أو sockaddr_un أو .... الخ ... الجواب هو عن طريق البرامتر الثالث الذي يحدد حجمة الــ Struct   الممرر ....

حيث :

sizeof(struct sockaddr_in) = 16
sizeof(struct sockaddr_in6) = 28

كي تفهم قصدي , انظر للمثال التالي :

#include <netinet/in.h>
#include<stdio.h>
#include<stdlib.h>
struct Student
{
	int ID;
	char *name;
};

struct Employee
{
	float age;
	float salary;
	float vacation;
};

void run (struct Student * s , int struct_Len)
{
	if (struct_Len == sizeof(struct Student))
	{
		printf("you passed Student to me : %d   %s \n" , s->ID , s->name);
		
	}else if (struct_Len == sizeof(struct Employee))
	{
		struct Employee * e = (struct Employee *) s;
		printf("you passed Employee to me : %f   %f   %f\n" , e->age , e->salary , e->vacation);
		
	}
}
main()
{
struct Student * stud = (struct Student*) malloc(sizeof(struct Student));
stud->ID = 10;
stud->name = "10";
run((struct Student *) stud , sizeof(struct Student));

struct Employee * emp = (struct Employee*) malloc(sizeof(struct Employee));
emp->age = 20;
emp->salary = 20;
emp->vacation = 20;
run((struct Student *) emp , sizeof(struct Employee));

printf("sizeof(struct Student) = %d\n" , sizeof(struct Student));
printf("sizeof(struct Employee) = %d\n" , sizeof(struct Employee));

return 0;
}

حيث يمكنني تمرير Employee  و Student  للدالة run  و لكن داخل الدالة , كيف سأعرف أن الوسيط الممر هو Employee  أم Sudent  الجواب عن طريق البرامتر الثالث ..

مراجع :

Setting sin_zero to 0 in struct sockaddr_in

تم تعديل هذه المشاركة بواسطة حسام الشامي في 11 ديسمبر 2013 في 12:56

3

لا إله إلا الله ... محمد رسول الله

لو كانت مشاركتي مفيدة و تريد تشجيعي على المزيد من العطاء , فضلا قم بتقييم المشاركة

المعرًف القديم : houssam11350_11350

من مواضيعي : ArabGenCode : مولد كود و إجراءات مخزنة و واجهات لجداول سيكوال سيرفر

#3

:)  بارك الله فيك اخي الشرح واضح وجميل اشكرك جدا على المساعدة..... :P 
 

#4
farid777 كتب:

:)  بارك الله فيك اخي الشرح واضح وجميل اشكرك جدا على المساعدة..... :P 

 

بارك الله بك .. بالتوفيق

لا إله إلا الله ... محمد رسول الله

لو كانت مشاركتي مفيدة و تريد تشجيعي على المزيد من العطاء , فضلا قم بتقييم المشاركة

المعرًف القديم : houssam11350_11350

من مواضيعي : ArabGenCode : مولد كود و إجراءات مخزنة و واجهات لجداول سيكوال سيرفر

هذا الموضوع مغلق.

مواضيع مشابهة