今天在看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