今天在看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
看看汇编代码:
.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