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

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页