unix网络编程进程通信 unpipc.h
https://blog.csdn.net/u010527630/article/details/33814377?spm=1001.2014.3001.5502
订阅专栏
1>解压源码unpv22e.tar.gz。
$tar zxvf unpv22e.tar.gz //这样源码就被解压到当前的目录下了
2>运行configure脚本,以生成正确的Makefile。为什么steven不直接写成Makefile,其实很简单,不同平台的Makefile不同,所以
直接写个脚本,然后在不同的平台上运行改脚本,该脚本会根据当前的平台生存正确的Makefile。
. / c o n f i g u r e / / 当前目录为源码的解压后的目录 3 > ./configure //当前目录为源码的解压后的目录 3> ./configure//当前目录为源码的解压后的目录3>cd lib
$make //编译,以生产lib文件
4>注释...再次make
5>拷贝unpipc.h和config.h到/usr/include下。同时修改unppic.h的第7行的config.h的路径为"config.h"。
拷贝libunpipc.a文件至/usr/lib和/usr/lib64下。
6>修改Make.defines。如果要使用Makefile文件的话,可以模仿steven先生的Makefile,不过他的Makefile的变量是Make.defines
里定义的,其中就有lib文件的路径,修改lib*.a文件的路为/usr/lib/lib*.a。
至此大功告成!可以像使用标准的头文件和库文件一样的使用steven的文件。使用steven的头文件并不难,难的是我不知道编译相关的知识而已。
unix 第一章 简介
1.1 概述
焦点是TCP/IP协议族,也称为网际协议族
安装程序
Unix NetWork Programming------环境搭建&第三版源码编译
c
1.(base) wannian07@wannian07-PC:~$ git clone https://github.com/maxliaops/Unix-Network-Programming.git
正克隆到 'Unix-Network-Programming'...
remote: Enumerating objects: 782, done.
remote: Total 782 (delta 0), reused 0 (delta 0), pack-reused 782
接收对象中: 100% (782/782), 579.66 KiB | 5.00 KiB/s, 完成.
处理 delta 中: 100% (115/115), 完成.
2.(base) wannian07@wannian07-PC:~$ cd Unix-Network-Programming/
3.(base) wannian07@wannian07-PC:~/Unix-Network-Programming$ chmod 755 configure
4.(base) wannian07@wannian07-PC:~/Unix-Network-Programming$ ./configure
checking build system type... x86_64-unknown-linux-gnu
checking host system type... x86_64-unknown-linux-gnu
checking for gcc... gcc
checking for C compiler default output... a.out
checking whether the C compiler works... yes
checking whether we are cross compiling... no
checking for suffix of executables...
checking for suffix of object files... o
checking whether we are using the GNU C compiler... yes
checking whether gcc accepts -g... yes
checking for gcc option to accept ANSI C... none needed
checking for ranlib... ranlib
checking for pthread_create in -lpthread... yes
checking for t_open in -lnsl... no
checking for library containing socket... none required
checking for /usr/local/bind/lib/libbind.a... no
checking for /home/wannian07/libbind.a... no
checking for /home/wannian07/libresolv.a... no
checking for res_init in -lresolv... no
checking for t_open in -lxti... no
checking for /home/wannian07/libunp.a... no
checking for /home/wannian07/libunpxti.a... no
checking how to run the C preprocessor... gcc -E
checking for egrep... grep -E
checking for ANSI C header files... yes
checking for sys/types.h... yes
checking for sys/socket.h... yes
checking for sys/time.h... yes
checking for time.h... yes
checking for netinet/in.h... yes
checking for arpa/inet.h... yes
checking for errno.h... yes
checking for fcntl.h... yes
checking for netdb.h... yes
checking for signal.h... yes
checking for stdio.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for sys/stat.h... yes
checking for sys/uio.h... yes
checking for unistd.h... yes
checking for sys/wait.h... yes
checking for sys/un.h... yes
checking for sys/param.h... yes
checking for sys/select.h... yes
checking for sys/sysctl.h... yes
checking for poll.h... yes
checking for sys/event.h... no
checking for strings.h... yes
checking for sys/ioctl.h... yes
checking for sys/filio.h... no
checking for sys/sockio.h... no
checking for pthread.h... yes
checking for net/if_dl.h... no
checking for xti.h... no
checking for xti_inet.h... no
checking for netconfig.h... no
checking for netdir.h... no
checking for stropts.h... yes
checking whether time.h and sys/time.h may both be included... yes
checking if uint8_t defined... yes
checking if int16_t defined... yes
checking if uint16_t defined... yes
checking if int32_t defined... yes
checking if uint32_t defined... yes
checking if size_t defined... yes
checking if ssize_t defined... yes
checking if socklen_t defined... yes
checking if sa_family_t defined... yes
checking if t_scalar_t defined... yes
checking if t_uscalar_t defined... yes
checking for struct sockaddr.sa_len... no
checking for struct sockaddr_storage... yes
checking for struct sockaddr_storage.ss_family... yes
checking for struct msghdr.msg_control... yes
checking for struct ifreq.ifr_mtu... yes
checking for getaddrinfo function prototype in netdb.h... yes
checking for getnameinfo function prototype in netdb.h... yes
checking for gethostname function prototype in unistd.h... yes
checking for getrusage function prototype in sys/resource.h... yes
checking for hstrerror function prototype in netdb.h... yes
checking for if_nametoindex function prototype in net/if.h... yes
checking for inet_aton function prototype in arpa/inet.h... yes
checking for inet_pton function prototype in arpa/inet.h... yes
checking for pselect function prototype in sys/select.h... yes
checking for snprintf function prototype in stdio.h... yes
checking for sockatmark function prototype in sys/socket.h... yes
checking for struct addrinfo... yes
checking for struct if_nameindex... yes
checking for struct sockaddr_dl... no
checking for struct timespec... yes
checking for /dev/tcp... no
checking for /dev/xti/tcp... no
checking for /dev/streams/xtiso/tcp... no
checking for bzero... yes
checking for getaddrinfo... yes
checking for gethostname... yes
checking for gethostbyname2... yes
checking for gethostbyname_r... yes
checking for getnameinfo... yes
checking for hstrerror... yes
checking for if_nametoindex... yes
checking for inet_aton... yes
checking for inet_pton... yes
checking for inet6_rth_init... yes
checking for kqueue... no
checking for kevent... no
checking for mkstemp... yes
checking for poll... yes
checking for pselect... yes
checking for snprintf... yes
checking for sockatmark... yes
checking for vsnprintf... yes
checking for IPv4 support... yes
checking for IPv6 support... yes
checking for Unix domain sockets... yes
checking for multicast support... yes
checking for -I/home/wannian07/doc/unp2ev1/src/include... no
configure: creating ./config.status
config.status: creating Makefile
config.status: creating Make.defines
config.status: creating config.h
5.(base) wannian07@wannian07-PC:~/Unix-Network-Programming$ cd lib
6.(base) wannian07@wannian07-PC:~/Unix-Network-Programming/lib$ make
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o connect_nonb.o connect_nonb.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o connect_timeo.o connect_timeo.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o daemon_inetd.o daemon_inetd.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o daemon_init.o daemon_init.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o dg_cli.o dg_cli.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o dg_echo.o dg_echo.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o error.o error.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o get_ifi_info.o get_ifi_info.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o gf_time.o gf_time.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o host_serv.o host_serv.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o family_to_level.o family_to_level.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o mcast_leave.o mcast_leave.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o mcast_join.o mcast_join.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o mcast_get_if.o mcast_get_if.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o mcast_get_loop.o mcast_get_loop.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o mcast_get_ttl.o mcast_get_ttl.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o mcast_set_if.o mcast_set_if.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o mcast_set_loop.o mcast_set_loop.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o mcast_set_ttl.o mcast_set_ttl.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o my_addrs.o my_addrs.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o read_fd.o read_fd.c
read_fd.c: In function 'read_fd':
read_fd.c:45:3: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
*recvfd = *((int *) CMSG_DATA(cmptr));
^
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o readline.o readline.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o readn.o readn.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o readable_timeo.o readable_timeo.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o rtt.o rtt.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o signal.o signal.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o signal_intr.o signal_intr.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o sock_bind_wild.o sock_bind_wild.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o sock_cmp_addr.o sock_cmp_addr.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o sock_cmp_port.o sock_cmp_port.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o sock_ntop.o sock_ntop.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o sock_ntop_host.o sock_ntop_host.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o sock_get_port.o sock_get_port.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o sock_set_addr.o sock_set_addr.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o sock_set_port.o sock_set_port.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o sock_set_wild.o sock_set_wild.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o sockfd_to_family.o sockfd_to_family.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o str_cli.o str_cli.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o str_echo.o str_echo.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o tcp_connect.o tcp_connect.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o tcp_listen.o tcp_listen.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o tv_sub.o tv_sub.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o udp_client.o udp_client.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o udp_connect.o udp_connect.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o udp_server.o udp_server.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o wraplib.o wraplib.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o wrapsock.o wrapsock.c
wrapsock.c: In function 'Inet6_rth_space':
wrapsock.c:81:8: warning: implicit declaration of function 'inet6_rth_space' [-Wimplicit-function-declaration]
ret = inet6_rth_space(type, segments);
^~~~~~~~~~~~~~~
wrapsock.c: In function 'Inet6_rth_init':
wrapsock.c:93:8: warning: implicit declaration of function 'inet6_rth_init' [-Wimplicit-function-declaration]
ret = inet6_rth_init(rthbuf, rthlen, type, segments);
^~~~~~~~~~~~~~
wrapsock.c:93:6: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
ret = inet6_rth_init(rthbuf, rthlen, type, segments);
^
wrapsock.c: In function 'Inet6_rth_add':
wrapsock.c:103:6: warning: implicit declaration of function 'inet6_rth_add' [-Wimplicit-function-declaration]
if (inet6_rth_add(rthbuf, addr) < 0)
^~~~~~~~~~~~~
wrapsock.c: In function 'Inet6_rth_reverse':
wrapsock.c:110:6: warning: implicit declaration of function 'inet6_rth_reverse' [-Wimplicit-function-declaration]
if (inet6_rth_reverse(in, out) < 0)
^~~~~~~~~~~~~~~~~
wrapsock.c: In function 'Inet6_rth_segments':
wrapsock.c:119:8: warning: implicit declaration of function 'inet6_rth_segments' [-Wimplicit-function-declaration]
ret = inet6_rth_segments(rthbuf);
^~~~~~~~~~~~~~~~~~
wrapsock.c: In function 'Inet6_rth_getaddr':
wrapsock.c:131:8: warning: implicit declaration of function 'inet6_rth_getaddr' [-Wimplicit-function-declaration]
ret = inet6_rth_getaddr(rthbuf, idx);
^~~~~~~~~~~~~~~~~
wrapsock.c:131:6: warning: assignment makes pointer from integer without a cast [-Wint-conversion]
ret = inet6_rth_getaddr(rthbuf, idx);
^
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o wrapstdio.o wrapstdio.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o wrappthread.o wrappthread.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o wrapunix.o wrapunix.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o write_fd.o write_fd.c
write_fd.c: In function 'write_fd':
write_fd.c:24:2: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
*((int *) CMSG_DATA(cmptr)) = sendfd;
^
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o writen.o writen.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o writable_timeo.o writable_timeo.c
ar rv ../libunp.a connect_nonb.o connect_timeo.o daemon_inetd.o daemon_init.o dg_cli.o dg_echo.o error.o get_ifi_info.o gf_time.o host_serv.o family_to_level.o mcast_leave.o mcast_join.o mcast_get_if.o mcast_get_loop.o mcast_get_ttl.o mcast_set_if.o mcast_set_loop.o mcast_set_ttl.o my_addrs.o read_fd.o readline.o readn.o readable_timeo.o rtt.o signal.o signal_intr.o sock_bind_wild.o sock_cmp_addr.o sock_cmp_port.o sock_ntop.o sock_ntop_host.o sock_get_port.o sock_set_addr.o sock_set_port.o sock_set_wild.o sockfd_to_family.o str_cli.o str_echo.o tcp_connect.o tcp_listen.o tv_sub.o udp_client.o udp_connect.o udp_server.o wraplib.o wrapsock.o wrapstdio.o wrappthread.o wrapunix.o write_fd.o writen.o writable_timeo.o
ar: 正在创建 ../libunp.a
a - connect_nonb.o
a - connect_timeo.o
a - daemon_inetd.o
a - daemon_init.o
a - dg_cli.o
a - dg_echo.o
a - error.o
a - get_ifi_info.o
a - gf_time.o
a - host_serv.o
a - family_to_level.o
a - mcast_leave.o
a - mcast_join.o
a - mcast_get_if.o
a - mcast_get_loop.o
a - mcast_get_ttl.o
a - mcast_set_if.o
a - mcast_set_loop.o
a - mcast_set_ttl.o
a - my_addrs.o
a - read_fd.o
a - readline.o
a - readn.o
a - readable_timeo.o
a - rtt.o
a - signal.o
a - signal_intr.o
a - sock_bind_wild.o
a - sock_cmp_addr.o
a - sock_cmp_port.o
a - sock_ntop.o
a - sock_ntop_host.o
a - sock_get_port.o
a - sock_set_addr.o
a - sock_set_port.o
a - sock_set_wild.o
a - sockfd_to_family.o
a - str_cli.o
a - str_echo.o
a - tcp_connect.o
a - tcp_listen.o
a - tv_sub.o
a - udp_client.o
a - udp_connect.o
a - udp_server.o
a - wraplib.o
a - wrapsock.o
a - wrapstdio.o
a - wrappthread.o
a - wrapunix.o
a - write_fd.o
a - writen.o
a - writable_timeo.o
ranlib ../libunp.a
7.(base) wannian07@wannian07-PC:~/Unix-Network-Programming/lib$ nm -g libunp.a
nm: libunp.a:无此文件
8.(base) wannian07@wannian07-PC:~/Unix-Network-Programming/lib$ cd ../libfree/
9.(base) wannian07@wannian07-PC:~/Unix-Network-Programming/libfree$ make
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o in_cksum.o in_cksum.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o inet_ntop.o inet_ntop.c
/usr/include/arpa/inet.h: In function 'inet_ntop':
inet_ntop.c:152:23: warning: 'best.len' may be used uninitialized in this function [-Wmaybe-uninitialized]
if (best.base == -1 || cur.len > best.len)
~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
inet_ntop.c:123:28: note: 'best.len' was declared here
struct { int base, len; } best, cur;
^~~~
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o inet_pton.o inet_pton.c
ar rv ../libunp.a in_cksum.o inet_ntop.o inet_pton.o
a - in_cksum.o
a - inet_ntop.o
a - inet_pton.o
ranlib ../libunp.a
(base) wannian07@wannian07-PC:~/Unix-Network-Programming/libfree$ cd ../libgai
(base) wannian07@wannian07-PC:~/Unix-Network-Programming/libgai$ make
ar rv ../libunp.a
ranlib ../libunp.a
10.(base) wannian07@wannian07-PC:~/Unix-Network-Programming/libgai$ cd ..
11.(base) wannian07@wannian07-PC:~/Unix-Network-Programming$ sudo cp libunp.a /usr/lib
[sudo] wannian07 的密码:
12.(base) wannian07@wannian07-PC:~/Unix-Network-Programming$ sudo cp libunp.a /usr/lib32
13.(base) wannian07@wannian07-PC:~/Unix-Network-Programming$ cd intro/
14.(base) wannian07@wannian07-PC:~/Unix-Network-Programming/intro$ make daytimetcpcli
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o daytimetcpcli.o daytimetcpcli.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -o daytimetcpcli daytimetcpcli.o ../libunp.a -lpthread
15.(base)wannian07@wannian07-PC:~/Unix-Network-Programming/intro$ ./daytimetcpcli
usage: a.out <IPaddress>
16.(base) wannian07@wannian07-PC:~/Unix-Network-Programming/intro$ ./daytimetcpcli 127.0.0.1
connect error: Connection refused
17.(base) wannian07@wannian07-PC:~/Unix-Network-Programming/intro$ make daytimetcpsrv
gcc -I../lib -g -O2 -D_REENTRANT -Wall -c -o daytimetcpsrv.o daytimetcpsrv.c
gcc -I../lib -g -O2 -D_REENTRANT -Wall -o daytimetcpsrv daytimetcpsrv.o ../libunp.a -lpthread
18.(base) wannian07@wannian07-PC:~/Unix-Network-Programming/intro$ sudo ./daytimetcpsrv &
[1] 13902
19. (base) wannian07@wannian07-PC:~/Unix-Network-Programming/intro$ ./daytimetcpcli 127.0.0.1
Sun Jun 2 21:18:53 2024
(base) wannian07@wannian07-PC:~/Desktop$ cd ...
(base) wannian07@wannian07-PC:~$ cd Unix-Network-Programming/
(base) wannian07@wannian07-PC:~/Unix-Network-Programming$ cd intro
测试的时候会出现如下错误connect error:Connection refused
第一种情况:没有xinetd.d,需要安装
sudo apt-get install xinetd
然后编辑daytime, wannian07@wannian07-PC# cd /etc/xinetd.d/
gedit daytime
将文件中的两个disable后面的yes改成no,保存退出
重启xinted.d
service xinetd restart
再次测试daytimetcpcli例子,
./daytimetcpcli 127.0.0.1
03 JUN 2024 18:45:28 CST
------------:https://blog.csdn.net/terence1212/article/details/51803268
c
#include "unp.h"
int main(int argc, char **argv){
union {
short s;
char c[sizeof(short)];
} un;
un.s = 0x0102;
printf("%s: ", CPU_VENDOR_OS);
if (sizeof(short) == 2) {
if (un.c[0] == 1 && un.c[1] == 2)
printf("big-endian\n");
else if (un.c[0] == 2 && un.c[1] == 1)
printf("little-endian\n");
else
printf("unknown\n");
} else
printf("sizeof(short) = %d\n", sizeof(short));
exit(0);
}
//~/Unix-Network-Programming/intro/byteorder.c
wannian07@wannian07-PC:~/Unix-Network-Programming/intro$ make byteorder
gcc -I.../lib -g -O2 -D_REENTRANT -Wall -c -o byteorder.o byteorder.c
byteorder.c: In function 'main':
byteorder.c:21:28: warning: format '%d' expects argument of type 'int', but argument 2 has type 'long unsigned int' [-Wformat=]
printf("sizeof(short) = %d\n", sizeof(short));
^
gcc -I.../lib -g -O2 -D_REENTRANT -Wall -o byteorder byteorder.o .../libunp.a -lpthread
(base) wannian07@wannian07-PC:~/Unix-Network-Programming/intro$ ./byteorder
x86_64-unknown-linux-gnu: little-endian
1.2 一个简单的时间获取客户程序
c
#include "unp.h"
int
main(int argc, char **argv)
{
int sockfd, n;
char recvline[MAXLINE + 1];
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: a.out <IPaddress>");
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
err_sys("socket error");
//bzero把整个结构清零后,置地址族为AF_INET, 端口好为13
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(13); //htons()主机到网络短整数
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0)//inet_pton呈现形式到数值
err_quit("inet_pton error for %s", argv[1]);
//IP地址为第一个命令行参数的值 argv[1]
if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
err_sys("connect error");
//在头文件unp.h中,我们使用#define把SA定义为struct sockaddr,也就是通用套接字地址结构。
while ( (n = read(sockfd, recvline, MAXLINE)) > 0) {
recvline[n] = 0; /* null terminate */
if (fputs(recvline, stdout) == EOF)
err_sys("fputs error");
}
if (n < 0)
err_sys("read error");
exit(0);
}
(base) wannian07@wannian07-PC:~/Unix-Network-Programming/intro$ make daytimetcpsrv
gcc -I.../lib -g -O2 -D_REENTRANT -Wall -c -o daytimetcpsrv.o daytimetcpsrv.c
gcc -I.../lib -g -O2 -D_REENTRANT -Wall -o daytimetcpsrv daytimetcpsrv.o .../libunp.a -lpthread
(base) wannian07@wannian07-PC:~/Unix-Network-Programming/intro$ sudo ./daytimetcpsrv &
1\] 13902
(base) wannian07@wannian07-PC:\~/Unix-Network-Programming/intro$ ./daytimetcpcli 127.0.0.1
Sun Jun 2 21:18:53 2024
bzero不是一个ANSI C函数。它起源于早期的Berkeley网络编程代码。在整本书中使用它而不用ANSI C的memset函数,因为bzero(带2个参数)比memset(带3个参数)更好记忆。几乎所有支持套接字API的厂商都提供bzero,如果没有,那么可以使用unp.h头文件中提供的该函数的宏定义。
connect函数应用于一个TCP套接字时,将与由它的第二个参数指向的套接字地址结构指定的服务器建立一个TCP连接。该套接字地址结构的长度也必须作为该函数的第三个参数指定,对于网际套接字地址结构,我们总是使用C语言的sizeof操作符由编译器来计算这个长度。
socket一词译者认为译成"套接口"
首先,作为网络编程API之一的套接口(sockets,注意这种用法总是采用复数形式,如sockets API、sockets library等)跟XTI一样,是应用层到传输层或其他协议层的访问接口。
其次,具体使用的套接口是与Unix管道的某一端类似的东西,我们既可以往这个"口"写数据,也可以从这个"口"读数据。
最后,套接口函数使用套接口描述字(discriptor)访问具体的套接口,如果把套接口描述字的简称sockfd译成"套接字"倒比较合适。一个套接口可对应多个套接字,因为Unix的描述字既可以复制,也可以继承;反过来,一个套接字对应且只对应一个套接口。
UDP(User Datagram Protocol,用户数据报协议)
TCP(Transmission Control Protocol,传输控制协议)
1、计算机网络各层对等实体间交换的单位信息称为协议数据单元(protocol data unit,PDU)
分节(segment)就是对应于TCP传输层的PDU。
按照协议与服务之间的关系,除了最低层(物理层)外,每层的PDU通过由紧邻下层提供给本层的服务接口,作为下层的服务数据单元(service data unit,SDU)传递给下层,并由下层间接完成本层的PDU交换。
同一层内SDU作为PDU的净荷(payload)字段出现,因此可以说上层PDU由本层PDU(通过其SDU字段)承载。每层的PDU除用于承载紧邻上层的PDU(即承载数据)外,也用于承载本层协议内部通信所需的控制信息。
如果本层的PDU大小超过紧邻下层的最大SDU限制,那么本层还要事先把PDU划分成若干个合适的片段让下层分开载送,再在相反方向把这些片段重组成PDU。
2、应用层实体(如客户或服务器进程)间交换的PDU称为应用数据(application data),其中在TCP应用进程之
间交换的是没有长度限制的单个双向字节流,在UDP应用进程之间交换的是其长度不超过UDP发送缓冲区大小的
单个记录(record),在SCTP应用进程之间交换的是没有总长度限制的单个或多个双向记录流。
传输层实体(例如对应某个端口的传输层协议代码的一次运行)间交换的PDU称为消息(message),其中TCP的PDU特称为分节(segment)。消息或分节的长度是有限的。
在TCP传输层中,发送端TCP把来自应用进程的字节流数据(即由应用进程通过一次次输出操作写出到发送端TCP套接字中的数据)
按顺序经分割后封装在各个分节中传送给接收端TCP,其中每个分节所封装的数据既可能是发送端应用进程单次输出操作的结果,
也可能是连续数次输出操作的结果,而且每个分节所封装的单次输出操作的结果或者首尾两次输出操作的结果既可能是完整的,也可能是不完整的,具体取决于可在连接建立阶段由对端通告的最大分节大小(maximum segment size,MSS)以及外出接口的最大传输单元(maximum transmission unit,MTU)或外出路径的路径MTU(如果网络层具有路径MTU发现功能,如IPv6)。
分节除了用于承载应用数据外,也用于建立连接(SYN分节)、终止连接(FIN分节)、中止连接(RST
分节)、确认数据接收(ACK分节)、刷送待发数据(PSH分节)和携带紧急数据指针(URG分节),而且这些功
能(包括承载数据)可以灵活组合。
UDP传输层相当简单,发送端UDP就把来自应用进程的单个记录整个封装在UDP消息中传送给接收端UDP。 SCTP引入了称为块(chunk)的数据单元,SCTP消息就由一个公共首部加上一个或多个块构成:公共首部类似UDP消息的首部,仅仅给出源目的端口号和整个SCTP消息的校验和;
块则既可以承载数据(称为DATA块),也可以承载控制信息(计有SACK块、INIT块、INIT ACK块、COOKIE ECHO块、COOKIEACK块、SHUTDOWN块、SHUTDOWN ACK块、SHUTDOWN COMPLETE块、ABORT块、ERROR块、HEARTBEAT块和HEARTBEAT ACK块,总称为控制块)。
送端SCTP把来自应用进程的(一个或多个)记录流数据按照流内顺序和记录边界封装在各个DATA块中,并在DATA块首部记上各自的流ID。一个记录通常对应一个DATA块;
对于过长的记录,发送端SCTP既可以像UDP那样拒绝发送,也可以把它们拆分到多个DATA块中以便发送,接收端SCTP收取后把它们组合成单个记录上传。
作为传输层PDU的SCTP消息既可以只包含单个块(DATA块或控制块),也可以在接口MTU或路径MTU的限制下包含多个块(称为块的捆绑,控制块在前,DATA块在后),不过INIT块、INIT ACK块和SHUTDOWN COMPLETE块不能跟任何其他块捆绑。SCTP收发两端均独立处理捆绑在同一个消息中的各个块,鉴于此,我们可以直接把块作为传输层PDU看待,本书也往往这么使用。
3、网络层实体间交换的PDU称为IP数据报(IP datagram),其长度有限:
IPv4数据报最大65 535字节,IPv6数据报最大65 575字节。
发送端IP把来自传输层的消息(或TCP分节)整个封装在IP数据报中传送。
链路层实体间交换的PDU称为帧(frame),其长度取决于具体的接口。
IP数据报由IP首部和所承载的传输层数据(即网络层的SDU)构成。过长的IP数据报无法封装在单个帧中,需要先对其SDU进行分片(fragmentation),再把分成的各个片段(fragment)冠以新的IP首部封装到多个帧中。
在一个IP数据报从源端到目的端的传送过程中,分片操作既可能发生在源端,也可能发生在途中,而其逆操作即重组(reassembly)一般只发生在目的端;
SCTP为了传送过长的记录采取了类似的分片和重组措施。
TCP/IP协议族为提高效率会尽可能避免IP的分片/重组操作:TCP根据MSS和MTU限定每个分节的大小以及SCTP根据MTU分片/重组过长记录都是这个目的(SCTP的块捆绑则是为了在避免IP分片/重组操作的前提下提高块传输效率);
另外,IPv6禁止在途中的分片操作(基于其路径MTU发现功能),IPv4也尽量避免这种操作。
不论是否分片,都由IP作为链路层的SDU传入链路层,并由链路层封装在帧中的数据称为分组(packet,俗称包)。可见一个分组既可能是一个完整的IP数据报,也可能是某个IP数据报的SDU的一个片段被冠以新的IP首部后的结果。另外,本书中讨论的MSS是应用层(TCP)与传输层之间的接口属性,MTU则是网络层和链路层之间的接口属性。
### 1.3 协议无关性
```c
#include "unp.h"
int
main(int argc, char **argv)
{
int sockfd, n;
struct sockaddr_in6 servaddr;
char recvline[MAXLINE + 1];
if (argc != 2)
err_quit("usage: a.out