unix網絡編程學習筆記1

今天在看UNPV1,4.4節的時候,當看到bind函數在綁定IP地址與端口號時UNP上說:

對於IPV4來說,通配地址由常值INADDR_ANY來指定,其值一般爲0;他告知內核去選擇IP地址。我們在圖1-9中隨如下賦值語句看到過它的使用:

structsockaddr_in   servaddr;

servaddr.sin_addr.s_addr= htonl (INADDR_ANY);     /* wildcard */

這對於IPV4而言是可行的,因爲其IP地址是一個32位的值,可以用一個簡單的數字常數表示,,對於IPV6就不可以這麼做了,因爲128位的IPV6地址存放在一個結構體中而這個成員又是一個字符數組,我們無法對其直接賦值。

Figure 3.1 The Internet (IPv4)socket address structure: sockaddr_in.

struct in_addr {

  in_addr_t   s_addr;           /* 32-bit IPv4 address */

                                /* network byteordered */

};

 

struct sockaddr_in {

  uint8_t         sin_len;      /* length of structure (16) */

  sa_family_t     sin_family;   /* AF_INET */

  in_port_t       sin_port;     /* 16-bit TCP or UDP port number */

                                /* network byteordered */

  structin_addr  sin_addr;     /* 32-bit IPv4 address */

                                /* network byteordered */

  char            sin_zero[8];  /* unused */

};


Figure 3.4 IPv6 socket addressstructure: sockaddr_in6.

struct in6_addr {

  uint8_t  s6_addr[16];          /* 128-bit IPv6 address */

                                 /* networkbyte ordered */

};

#define SIN6_LEN     /* required for compile-time tests */

struct sockaddr_in6 {

  uint8_t         sin6_len;      /* length of this struct (28) */

  sa_family_t     sin6_family;   /* AF_INET6 */

  in_port_t       sin6_port;     /* transport layer port# */

                                 /* networkbyte ordered */

  uint32_t        sin6_flowinfo; /* flow information,undefined */

  struct in6_addrsin6_addr;     /* IPv6 address */

                                 /* networkbyte ordered */

  uint32_t        sin6_scope_id; /* set of interfaces fora scope */

};

數組不能直接賦值。如果直接複製就會出錯。例如:

 

#include<stdio.h>

 

int main()

{

   int a[5],b[5],i;

   for(i=0;i<5;i++)

   {  

       a[i]=i;   

   }

   b=a;

   return 0;

}

[xufubo@localhost unppro]$ gcc -std=c99  carray.c -o carray

carray.c: In function ‘main’:

carray.c:10: error: incompatible types when assigning totype ‘int[5]’ from type ‘int *’

但是書中說系統是這麼處理的:

struct sockaddr_in6    serv;
serv.sin6_addr = in6addr_any;     /* wildcard */

並解釋如下:

由於C語言中賦值語句的右邊無法表示常值結構,所以系統預先分配了in6addr_any 變量並初始化爲IN6ADDR_ANY_INIT. 頭文件<netinet/in.h>包含了in6addr_any的extern聲明。這句話也說明了如下一個事實,數組不可以直接賦值,但是如果數組作爲結構體的成員則可以通過結構體的賦值而實現數組的賦值與賦值。如下案例證明確實如此:

#include<stdio.h>

 

struct test1{

   int a;

   double b;

};

struct test2{

   int c;

   double d;

   int arr[5];

};

int main()

{

   struct test1 demo11,demo12;

   struct test2 demo21,demo22;

   int i,j;

   demo11.a=3;

   demo11.b=4.5;

   demo12=demo11;

   demo21.c=67;

   demo22.d=9.5;

   for(i=0;i<5;i++)

   {  

       demo21.arr[i]=i;   

   }

   demo22=demo21;

   for(i=0;i<5;i++)

   {  

       printf("%d\n",demo21.arr[i]);   

   }

   for(j=0;j<5;j++)

   {  

       printf("%d\n",demo22.arr[j]);  

  

   }

   printf("%d,%lf\n",demo11.a,demo11.b);

   printf("%d,%lf\n",demo12.a,demo12.b);

   return 0;

 

}


    編譯並且運行:

[xufubo@localhostunppro]$ gcc -std=c99  struct.c -o struct

[xufubo@localhostunppro]$ ./struct

0

1

2

3

4

0

1

2

3

4

3,4.500000

3,4.500000


看看彙編代碼:

 

   .file  "struct.c"

   .section   .rodata

.LC2:

   .string    "%d\n"

.LC3:

   .string    "%d,%lf\n"

   .text

.globl main

   .type  main, @function

main:

   pushl  %ebp

   movl   %esp, %ebp

   andl   $-16, %esp

   subl   $112, %esp

   movl   $3, 92(%esp)

   fldl   .LC0

   fstpl  96(%esp)

   movl   92(%esp), %eax

   movl   %eax, 80(%esp)

   movl   96(%esp), %eax

   movl   %eax, 84(%esp)

   movl   100(%esp), %eax

   movl   %eax, 88(%esp)

   movl   $67, 48(%esp)

   fldl   .LC1

   fstpl  20(%esp)

   movl   $0, 104(%esp)

   jmp .L2

.L3:

   movl   104(%esp), %eax

   movl   104(%esp), %edx

   movl   %edx, 60(%esp,%eax,4)

   addl   $1, 104(%esp)

.L2:

   cmpl   $4, 104(%esp)

   jle .L3

   movl   48(%esp), %eax

   movl   %eax, 16(%esp)

   movl   52(%esp), %eax

   movl   %eax, 20(%esp)

   movl   56(%esp), %eax

   movl   %eax, 24(%esp)

   movl   60(%esp), %eax

   movl   %eax, 28(%esp)

   movl   64(%esp), %eax

   movl   %eax, 32(%esp)

   movl   68(%esp), %eax

   movl   %eax, 36(%esp)

   movl   72(%esp), %eax

   movl   %eax, 40(%esp)

   movl   76(%esp), %eax

   movl   %eax, 44(%esp)

   movl   $0, 104(%esp)

   jmp .L4

.L5:

   movl   104(%esp), %eax

   movl   60(%esp,%eax,4), %edx

   movl   $.LC2, %eax

   movl   %edx, 4(%esp)

   movl   %eax, (%esp)

   call   printf

   addl   $1, 104(%esp)

.L4:

   cmpl   $4, 104(%esp)

   jle .L5

   movl   $0, 108(%esp)

   jmp .L6

.L7:

   movl   108(%esp), %eax

   movl   28(%esp,%eax,4), %edx

   movl   $.LC2, %eax

   movl   %edx, 4(%esp)

   movl   %eax, (%esp)

   call   printf

   addl   $1, 108(%esp)

.L6:

   cmpl   $4, 108(%esp)

   jle .L7

   fldl   96(%esp)

   movl   92(%esp), %edx

   movl   $.LC3, %eax

   fstpl  8(%esp)

   movl   %edx, 4(%esp)

   movl   %eax, (%esp)

   call   printf

   fldl   84(%esp)

   movl   80(%esp), %edx

   movl   $.LC3, %eax

   fstpl  8(%esp)

   movl   %edx, 4(%esp)

   movl   %eax, (%esp)

   call   printf

   movl   $0, %eax

   leave

   ret

   .size  main, .-main

   .section   .rodata

   .align8

.LC0:

   .long  0

   .long  1074921472

   .align8

.LC1:

   .long  0

   .long  1076035584

   .ident "GCC: (GNU) 4.4.7 20120313 (Red Hat4.4.7-3)"

   .section   .note.GNU-stack,"",@progbits

通過上邊我們可以學習到這麼一個經驗:

當我們想要返回數組,或者想要對數組實現賦值時可以把數組定義在結構體中,通過結構體之間的賦值來實現數組的複製,這是真正的數組元素的複製,並沒有將其退化爲指針,如果在上邊程序加上這麼一句:

printf("%x,%x\n",demo21.arr,demo22.arr);

將會有如下輸出:

bfd17d8c,bfd17d6c

可見兩個數組的確不同,實現的真正的數組內存的複製。

即結構體的賦值,是直接結構體的內存的拷貝!但正是這個問題,如下邊的實例,foo1 和 foo2 中p_c 指針都是指向我們申請的一塊大小爲4個字節的內存區域,這裏注意的是,結構體的拷貝只是淺拷貝,即指針p_c的賦值並不會導致再申請一塊內存區域,讓foo2的p_c指向它。那麼,如果釋放掉foo1中的p_c指向的內存,此時foo2中p_c變成懸掛指針,這時對foo2的p_c操作就會出現一些不可預見的問題。在C++中引入了一種可以允許用戶重載結構體賦值操作運算,那麼我們就可以根據語義重載賦值操作。

 

#include<stdio.h>

#include<stdlib.h>

 

struct Foo {

    int n;

    double d[2];

    char *p_c;

}foo1, foo2;

 

int main()

{

    char *c = (char *) malloc (4*sizeof(char));

    c[0] = 'a'; c[1] = 'b'; c[2] = 'c'; c[3] ='\0';

 

    foo1.n = 1;

    foo1.d[0] = 2; foo1.d[1] = 3;

    foo1.p_c = c;

 

    foo2 = foo1;     //assign foo1 to foo2

 

    printf("%d ,%lf ,%lf,%x,%x,%x,%x\n", foo2.n, foo2.d[0], foo2.d[1],foo1.p_c,foo2.p_c,foo1.d,foo2.d);

 

    return 0;

}

[xufubo@localhostunppro]$ gcc -std=c99  dstruct.c -odstruct

[xufubo@localhostunppro]$ ./dstruct

1 ,2.000000,3.000000 ,91d5008,91d5008,80497bc,80497a4

[xufubo@localhostunppro]$

UNIX網絡編程的一些其他筆記

Vmware  10全屏後隱藏工具條:查看——>獨佔模式就ok。

Root登陸後運行服務器程序:看到daytimetcpsrv是bash的子進程

├─konsole─┬─bash                                         

     │         └─{konsole}                                    

     ├─konsole─┬─bash───su───bash─┬─daytimetcpsrv             

     │         │                  └─pstree                    

     │         └─{konsole}                                     

Exit後:進程樹如下:

init─┬─NetworkManager───{NetworkManager}

             ……………………………….

     ├─crond                                                   

     ├─cupsd                                                  

     ├─daytimetcpsrv                                          

     ├─2*[dbus-daemon───{dbus-daemon}]      

果然爲了避免 daytimetcpsrv成爲殭屍進程,daytimetcpsrv成了init的子進程。  

 

Linux中,errno在 <errno.h> 中定義,錯誤 Exx 的宏定義在 /usr/include/asm-generic 文件夾下面的 errno-base.h 和 errno.h,分別定義了 1-34 、35-134 的錯誤定義。

strerror() 函數依據 errno 值返回錯誤描述字符串,下面程序打印對照表:

1.   #include <errno.h>  

2.   #include <string.h>  

3.   #include <stdio.h>  

4.     

5.   int main()  

6.   {  

7.       int i;  

8.       for(i = 0; i < 140; ++i)  

9.       {  

10.         errno = i;  

11.             printf("errno %d :\t\t%s\n",i,strerror(errno));  

12.     }  

13.     return 0;  

14. }  


而UNIX下面errno則在/usr/include/sys/errno.h中定義。

在文件中查找:

grep  ‘refused’ /usr/include/asm-generic/errno.h.

在目錄中查找有關的文件:

ls | grep 'unp'

結果:

    unpv13e

unpv13e.tar.gz

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章