板凳-------unix 网络编程 卷1-1简介

news2024/10/16 16:02:37

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——环境搭建&第三版源码编译

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

#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 一个简单的时间获取客户程序


#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 协议无关性

#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 <IPaddress>");

	if ( (sockfd = socket(AF_INET6, SOCK_STREAM, 0)) < 0)
		err_sys("socket error");

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin6_family = AF_INET6;
	servaddr.sin6_port   = htons(13);	/* daytime server */
	if (inet_pton(AF_INET6, argv[1], &servaddr.sin6_addr) <= 0)
		err_quit("inet_pton error for %s", argv[1]);

	if (connect(sockfd, (SA *) &servaddr, sizeof(servaddr)) < 0)
		err_sys("connect error");

	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);
}

用户必须以点分十进制数格式给出服务器的IP地址(如适合于IPv4版本的206.168.112.219)。人们更习惯于用名字(如www.unpbook.com)来代替数字。

1.4 错误处理:包裹函数

既然发生错误时终止程序的运行是普遍的情况,我们可以通过定义包裹函数(wrapper function)来缩短程序。每个包裹函数完成实际的函数调用,检查返回值,并在发生错误时终止进程。我们约定包裹函数名是实际函数名的首字母大写形式。
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
中,函数Socket是函数socket的包裹函数,只要你遇到一个首字母大写的函数名,它就是我们定义的某个包裹函数。它调用的实际函数的名字与包裹函数名相同,不过以对应的小写字母开头。

1.5 一个简单的时间获取服务器程序

#include	"unp.h"
#include	<time.h>

int
main(int argc, char **argv)
{
	int					listenfd, connfd;
	struct sockaddr_in	servaddr;
	char				buff[MAXLINE];
	time_t				ticks;

	listenfd = Socket(AF_INET, SOCK_STREAM, 0);

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family      = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port        = htons(13);	/* daytime server */

	Bind(listenfd, (SA *) &servaddr, sizeof(servaddr));

	Listen(listenfd, LISTENQ);

	for ( ; ; ) {
		connfd = Accept(listenfd, (SA *) NULL, NULL);

        ticks = time(NULL);
        snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
        Write(connfd, buff, strlen(buff));

		Close(connfd);
	}
}

把套接字转换成监听套接字
调用listen函数把该套接字转换成一个监听套接字,这样来自客户的外来连接就可在该套接字上由内核接受。socket、bind和listen这3个调用步骤是任何TCP服务器准备所谓的监听描述符(listening descriptor,本例中为listenfd)的正常步骤。常值LISTENQ在我们的unp.h头文件中定义。它指定系统内核允许在这个监听描述符上排队的最大客户连接数。
接受客户连接,发送应答
通常情况下,服务器进程在accept调用中被置于休眠状态,等待某个客户连接的到达并被内核接受。TCP连接使用所谓的三路握手(three-way handshake)来建立连接。握手完毕时accept返回,其返回值是一个称为已连接描述符(connected descriptor)的新描述符(本例中为connfd)。该描述符用于与新近连接的那个客户通信。accept为每个连接到本服务器的客户返回一个新描述符。
当前时间和日期是由库函数time返回的,它实际上返回的是自Unix纪元即1970年1月1日0点0分0秒(国际标准时间)以来的秒数。下一个库函数ctime把该整数值转换成直观可读的时间格式,例如:
Mon May 26 20:58:40 2003
snprintf函数在这个字符串末尾添加一个回车符和一个回行符,随后write函数把结果字符串写给客户。调用sprintf无法检查目的缓冲区是否溢出。相反,snprintf要求其第二个参数指定目的缓冲区的大小,因此可确保该缓冲区不溢出。必须小心使用的函数还有gets、strcat和strcpy,通常应分别改为调用fgets、strncat和strncpy。更好的替代函数是后来才引入的strlcat和strlcpy,它们确保结果是正确终止的字符串。
注意。
与其客户程序一样,这一服务器程序也与IPv4协议相关。
本服务器一次只能处理一个客户。如果多个客户连接差不多同时到达,系统内核在某个最大数目的限制下把它们排入队列,然后每次返回一个给accept函数。本服务器只需调用time和ctime这两个库函数,运行速度很快。然而如果服务器需用较多时间(譬如说几秒钟或一分钟)服务每个客户,那么我们必须以某种方式重叠对各个客户的服务。所示的服务器称为迭代服务器(iterative server),因为对于每个客户它都迭代执行一次。同时能处理多个客户的并发服务器(concurrent server)有多种编写技术。最简单的技术是调用Unix的fork函数(4.7节),为每个客户创建一个子进程。其他技术包括使用线程代替fork(26.4节),或在服务器启动时预先fork一定数量的子进程(30.6节)。
如果从shell命令行启动本例这样的一个服务器,我们也许想要它运行很长时间,因为服务器往往在系统工作期间一直运行。这要求我们往服务器程序中添加代码,以便它能够作为一个Unix守护进程(daemon)—能在后台运行且不跟任何终端关联的进程—运行。

1.6 本书中客户/服务器程序示例索引表

1.7 OSI 模型

在这里插入图片描述

OSI模型的底下两层是随系统提供的设备驱动程序和网络硬件。通常情况下,除需知道数据链路的某些特性外(如将在2.11节论述的1500字节以太网的MTU大小)
网络层由IPv4和IPv6这两个协议处理。可以选择的传输层有TCP或UDP。图1-14中TCP与UDP之间留有间隙,表明网络应用绕过传输层直接使用IPv4或IPv6是可能的。这就是所谓的原始套接字(raw socket)。
OSI模型的顶上三层被合并成一层,称为应用层。这就是Web客户(浏览器)、Telnet客户、Web服务器、FTP服务器和其他我们在使用的网络应用所在的层。对于网际协议,OSI模型的顶上三层协议几乎没有区别。
套接字编程接口是从顶上三层(网际协议的应用层)进入传输层的接口。焦点是:如何使用套接字编写使用TCP或UDP的网络应用程序。已提到原始套接字,甚至可以彻底绕过IP层直接读写数据链路层的帧。
为什么套接字提供的是从OSI模型的顶上三层进入传输层的接口?这样设计有两个理由:
一、是顶上三层处理具体网络应用(如FTP、Telnet或HTTP)的所有细节,却对通信细节了解很少;底下四层对具体网络应用了解不多,却处理所有的通信细节:发送数据,等待确认,给无序到达的数据排序,计算并验证校验和,等等。
二、顶上三层通常构成所谓的用户进程(user process),底下四层却通常作为操作系统内核的一部分提供。Unix与其他现代操作系统都提供分隔用户进程与内核的机制。由此可见,第4层和第5层之间的接口是构建API的自然位置。

1.8 BSD 网络支持历史

1.9 测试用网络及主机

(1) netstat -i提供网络接口的信息。
(base) wannian07@wannian07-PC:~/Desktop$ netstat -ni
Kernel Interface table
Iface MTU RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP TX-OVR Flg
lo 65536 12174 0 0 0 12174 0 0 0 LRU
wlp1s0 1500 37 0 308 0 157 0 0 0 BMU
(base) wannian07@wannian07-PC:~/Desktop$ netstat -nr
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface

1.10 Unix 标准

POSIX(可移植操作系统接口)是Portable Operating System Interface的首字母缩写。它并不是单个标准,而是由电气与电子工程师学会(the Institute for Electrical and Electronics Engineers, Inc.)即IEEE开发的一系列标准。POSIX标准已被国际标准化组织即ISO和国际电工委员会(the International Electrotechnical Commission)即IEC采纳为国际标准(这两个组织合称为ISO/IEC)。
本书的焦点是单一Unix规范第3版,其中又以套接字API为主。只要可能,我们就使用标准函数

1.11 64 位体系结构

1.12 小结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1843595.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于51单片机的篮球计分器设计

一.硬件方案 本设计用由AT89C51编程控制LED七段数码管作显示的球赛计时计分系统。该系统具有赛程定时设置、赛程时间暂停、及时刷新甲乙双方的成绩等功能。 电路主要由STC89C52单片机最小系统数码管显示模块数码管驱动模块蜂鸣器模块按键模块&#xff1b; 二.设计功能 &…

Flow Matching For Generative Modeling

Flow Matching For Generative Modeling 一、基于流的&#xff08;Flow based&#xff09;生成模型 生成模型 我们先回顾一下所谓的生成任务&#xff0c;究竟是想要做什么事情。我们认为&#xff0c;世界上所有的图片&#xff0c;是符合某种分布 p d a t a ( x ) p_{data}(…

Serverless如何赋能餐饮行业数字化?乐凯撒思变之道

导语 | 在数字化浪潮席卷全球的今天&#xff0c;每一个行业都在经历着前所未有的变革。餐饮行业作为人们日常生活中不可或缺的一部分&#xff0c;更是面临着巨大的转型压力。如何完成数字化转型&#xff0c;打破传统经营模式的限制&#xff0c;成为摆在众多餐饮商家面前的一道难…

基于Docker搭建ELK(Elasticsearch、Logstash、Kibana)日志框架

一、引言 随着企业业务的不断增长&#xff0c;日志管理成为了系统运维中不可或缺的一部分。ELK&#xff08;Elasticsearch、Logstash、Kibana&#xff09;作为一套开源的日志管理系统&#xff0c;以其高效、灵活、可扩展的特性&#xff0c;成为了众多企业的首选。本文将详细介…

代码随想录刷题复习day01

day01 数组-二分查找 class Solution {public int search(int[] nums, int target) {// 左闭右闭int left 0;int right nums.length - 1;int mid 0;while (right > left) {mid left (right - left) / 2;if (nums[mid] > target)right mid - 1;else if (nums[mid]…

机器学习案例|使用机器学习轻松预测信用卡坏账风险,极大程度降低损失

01、案例说明 对于模型的参数&#xff0c;除了使用系统的设定值之外&#xff0c;可以进行再进一步的优化而得到更好的结果。RM提供了几种参数优化的方法&#xff0c;能够让整体模型的效率提高。而其使用的概念&#xff0c;仍然是使用计算机强大的计算能力&#xff0c;对于不同…

动态轮换代理在多账户管理中有何用处?

如果您要处理多个在线帐户&#xff0c;选择正确的代理类型对于实现流畅的性能至关重要。但最适合这项工作的代理类型是什么&#xff1f; 为了更好地管理不同平台上的多个账户并优化成本&#xff0c;动态住宅代理IP通常作用在此。 一、什么是轮换代理&#xff1f; 轮换代理充当…

SpringSecurity实战入门——认证

项目代码 gson/spring-security-demo 简介 Spring Security 是 Spring 家族中的一个安全管理框架。相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。 一般来说中大型的项目都是使用SpringSecurity来做安全框架。小项目有Shiro的比较多,因为相比…

探索交互设计:五大关键维度全面剖析

交互式设计是用户体验&#xff08;UX&#xff09;设计的重要组成部分。在本文中&#xff0c;我将向大家解释什么是交互设计并简要描述交互设计师通常每天都做什么。 一、什么是交互设计 交互式设计用简单的术语来理解就是用户和产品之间的交互。在大多数情况下&#xff0c;当…

嵌入式Linux 中常见外设屏接口分析

今天将梳理下嵌入式外设屏幕接口相关的介绍,对于一个嵌入式驱动开发工程师,对屏幕都可能接触到一些相关的的调试,这里首先把基础相关的知识梳理。 1. 引言 在嵌入式开发过程中,使用到的液晶屏有非常多的种类,根据不同技术和特性分类,会接触到TN液晶屏,TN液晶屏 VA液晶屏…

JDBC(简介、入门与IDEA中导入MySQL的驱动)

&#xff08;建议学完 MySQL 的基础部分&#xff09; JDBC——简而言之&#xff1a;用 Java 语言操作数据库。 Java DataBase Connectivity&#xff08;Java 语言连接数据库&#xff09; 目录 一、引言 &#xff08;1&#xff09;基本介绍 &#xff08;2&#xff09;JDBC 简…

【代码随想录】【算法训练营】【第44天】 [322]零钱兑换 [279]完全平方数 [139]单词拆分

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 44&#xff0c;周四&#xff0c;坚持不住了~ 题目详情 [322] 零钱兑换 题目描述 322 零钱兑换 解题思路 前提&#xff1a; 思路&#xff1a; 重点&#xff1a; 代码实现 C语言 [279] 完全…

代码随想录算法训练营第29天(贪心)|455.分发饼干、376. 摆动序列、53. 最大子序和

455.分发饼干 题目链接&#xff1a;455.分发饼干 文档讲解&#xff1a;代码随想录 状态&#xff1a;so easy 思路&#xff1a;对胃口和饼干大小排序&#xff0c;小胃口对应小饼干&#xff0c;不满足的话用下一块饼干试探。 题解&#xff1a; public int findContentChildren(i…

自动化测试Robot FrameWork框架

一、简介 Robot FrameWork是完全基于Python实现的开源的自动化测试框架&#xff0c;RF已经封装好的各个模块&#xff0c;基于关键字驱动的形式来实现的自动化测试。其case采用表格形式易读&#xff0c;且支持BDD&#xff0c;可容纳各种外置库&#xff0c;可以继承Selenium、Ap…

【机器学习】基于稀疏识别方法的洛伦兹混沌系统预测

1. 引言 1.1. DNN模型的来由 从数据中识别非线性动态学意味着什么&#xff1f; 假设我们有时间序列数据&#xff0c;这些数据来自一个&#xff08;非线性&#xff09;动态学系统。 识别一个系统意味着基于数据推断该系统的控制方程。换句话说&#xff0c;就是找到动态系统方…

【etcd】etcd单机安装及简单操作

https://blog.csdn.net/Mr_XiMu/article/details/125026635 https://blog.csdn.net/m0_73192864/article/details/136509244 etcd在生产环境中一般为集群方式部署 etcd使用的2个默认端口号&#xff1a;2379和2380 2379&#xff1a;用于客户端通信(类似于sqlserver的1433&#x…

视频融合共享平台LntonCVS视频监控安防系统运用多视频协议建设智慧园区方案

智慧园区&#xff0c;作为现代化城市发展的重要组成部分&#xff0c;不仅推动了产业的升级转型&#xff0c;也成为了智慧城市建设的核心力量。随着产业园区之间的竞争日益激烈&#xff0c;如何打造一个功能完善、智能化程度高的智慧园区&#xff0c;已经成为了业界广泛关注的焦…

五十、openlayers官网示例JSTS Integration解析——使用JSTS 库来处理几何缓冲区并在地图上显示结果

官网demo地址&#xff1a; JSTS Integration 这篇讲了如何在地图上添加缓冲图形 什么叫做缓冲几何&#xff1f; 几何缓冲&#xff08;Geometric Buffering&#xff09;是指在 GIS&#xff08;地理信息系统&#xff09;和计算几何中&#xff0c;围绕一个几何对象创建一个具有…

时空预测 | 基于深度学习的碳排放时空预测模型

时空预测 模型描述 数据收集和准备&#xff1a;收集与碳排放相关的数据&#xff0c;包括历史碳排放数据、气象数据、人口密度数据等。确保数据的质量和完整性&#xff0c;并进行必要的数据清洗和预处理。 特征工程&#xff1a;根据问题的需求和领域知识&#xff0c;对数据进行…

Walrus:去中心化存储和DA协议,可以基于Sui构建L2和大型存储

Walrus是为区块链应用和自主代理提供的创新去中心化存储网络。Walrus存储系统今天以开发者预览版的形式发布&#xff0c;面向Sui开发者征求反馈意见&#xff0c;并预计很快会向其他Web3社区广泛推广。 通过采用纠删编码创新技术&#xff0c;Walrus能够快速且稳健地将非结构化数…