第一章 理解网络编程和套接字

  1. 套接字在网络编程中的作用是什么?为什么称它为套接字?

    P2,网络编程就是编写程序让两台联网的计算机相互交换数据。在我们不需要考虑物理连接的情况下,我们只需要考虑如何编写传输软件。操作系统提供了名为“套接字”,套接字是网络传输传输用的软件设备

    socket英文原意是插座:我们把插头插到插座上就能从电网获得电力供给,同样,为了与远程计算机进行数据传输,需要连接到Internet,而变成中的“套接字”就是用来连接该网络的工具

  2. 在服务器端创建套接字后,会依次调用listen函数和accept函数。请比较并说明两者作用

    listen:将套接字转为可接受连接方式

    accept:受理连接请求,并且在没有连接请求的情况调用该函数,不会返回。直到有连接请求为止。二者存在逻辑上的先后关系

  3. Linux中,对套接字数据进行I/O时可以直接使用I/O相关函数;而在Windows中则不可以。原因为何?

    Linux把套接字也看作是文件,所以可以用文件I/O相关函数;而Windows要区分套接字和文件,所以设置了特殊的函数

  4. 创建套接字后一般会给它分配地址,为什么?为了完成地址分配需要调用哪些函数?

    要在网络上区分来自不同机器的套接字,所以需要地址信息。分配地址是通过bind()函数实现

  5. Linux中的文件描述符与Windows的句柄实际上非常类似。请以套接字为对象说明他们的含义。

    Linux的文件描述符是为了区分指定文件而赋予文件的整数值(相当于编号)。Windows的文件描述符其实也是套接字的整数值,其目的也是区分指定套接字。

  6. 底层文件I/O函数与ANSI标准定义的文件I/O函数之间有何区别?

    ANSI标准定义的输入、输出函数是与操作系统(内核)无关的以C标准写成的函数。相反,底层文件I/O函数是直接提供的。理论上ANSI标准I/O提供了某些机制,性能上由于底层I/O

  7. 参考本书给出的示例low_open.c和low_read.c,分别利用底层文件I/O和ANSI标准I/O编写文件复制程序。可任意指定复制程序的使用方法

第二章:套接字类型与协议设置

  1. 什么是协议?在收发数据中定义协议有何意义?

    协议就是为了完成数据交换而定好的约定。因此,定义协议意味着对数据传输所必需的的承诺进行定义。

  2. 面向连接的TCP套接字传输特性有3点,请分别说明。

    • 传输过程中数据不会丢失
    • 按序传输数据
    • 传输的数据不存在数据边界(Boundary)
  3. 下面哪些是面向消息的套接字的特性?a、c、e

  4. UDP 、TCP 、TCP

  5. 何种类型的套接字不存在数据边界?这类套接字接收数据时需要注意什么?

    连接指向型TCP套接字不存在数据边界。因此输入输出函数的响应次数不具有意义。重要的不是函数的响应次数,而是数据的收发量。因此,必须将传输数据的量和接收数据的量制作成编码,保证发送数据的量和接收数据的量是一致的,特别要注意是制作依赖函数响应次数判断代码

  6. 修改代码

/*****************************tcp_serv.c*********************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>void error_handling(char *message);int main(int argc, char *argv[])
{int serv_sock;int clnt_sock;struct sockaddr_in serv_addr;struct sockaddr_in clnt_addr;socklen_t clnt_addr_size;char message[]="Hello World!";if(argc!=2){printf("Usage : %s <port>\n", argv[0]);exit(1);}serv_sock=socket(PF_INET, SOCK_STREAM, 0);if(serv_sock == -1)error_handling("socket() error");memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family=AF_INET;serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);serv_addr.sin_port=htons(atoi(argv[1]));if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr))==-1)error_handling("bind() error"); if(listen(serv_sock, 5)==-1)error_handling("listen() error");clnt_addr_size=sizeof(clnt_addr);  clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size);if(clnt_sock==-1)error_handling("accept() error");  write(clnt_sock, message, 4);write(clnt_sock, message+4, 4);write(clnt_sock, message+8, 4);write(clnt_sock, message+12, sizeof(message)-12);close(clnt_sock);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}/*****************************tcp_clnt.c*********************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>void error_handling(char *message);int main(int argc, char* argv[])
{int sock;struct sockaddr_in serv_addr;char message[30];int str_len=0;int idx=0, read_len=0, i;if(argc!=3){printf("Usage : %s <IP> <port>\n", argv[0]);exit(1);}sock=socket(PF_INET, SOCK_STREAM, 0);if(sock == -1)error_handling("socket() error");memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family=AF_INET;serv_addr.sin_addr.s_addr=inet_addr(argv[1]);serv_addr.sin_port=htons(atoi(argv[2]));if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1) error_handling("connect() error!");for(i=0; i<100; i++)       // busy waiting!!printf("Wait time %d \n", i);read(sock, message, sizeof(message));printf("Message from server: %s \n", message);close(sock);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}

第三章 地址族与数据序列

  1. IP地址族IPv4和IPv6有何区别?在何种背景下诞生了IPv6?

    IPV4是4字节地址族,IPV6是16字节地址族。IPV6的诞生是为了应对2010年前后IP地址耗尽的问题而提出的标准

  2. 通过IPV4网络ID、主机ID及路由器的关系说明向公司局域网中的计算机传输数据的过程

    首先数据传输的第一个环节是向目标IP所属的网络传输数据。此时使用的是IP地址中的网络ID。传输的数据将被传到管理网络的路由器,接受数据的路由器将参照IP地址的主机号找自己保存的路由表,找到对应的主机发送数据

  3. 套接字地址分为IP地址和端口号。为什么需要IP地址和端口号?或者说,通过IP可以区分哪些对象?通过端口号可以区分哪些对象?

    IP地址是为了区分网络上的主机。端口号是区分同一主机下的不同的SOCKET,以确保软件准确收发数据。

  4. CAB

  5. 计算机通过路由器或交换机连接到互联网。请说出路由器和交换机的作用

    路由器是帮助数据传输到目的地的中介。不仅如此,还起到帮助连接本地网络的电脑和互联网的作用

  6. 什么是知名端口?其范围是多少?知名端口中具有代表性的HTTP合同FTP端口号各是多少?

    “知名端口(Well-known PROT)”是指预定分配给特定操作的端口。其范围是0~1023,其中最知名的端口是HTTP:80端口和TCP:21

  7. 题目大概意思是:为什么bind中第二个参数是sockaddr,但是传入的是sockaddr_in

bind函数第二个参数类型是sockaddr结构体,很难份分配IP地址和端口号,因此IP地址和PORT号的分配是通过sockaddr_in完成的。因为该结构体和sockaddr结构体的组成字节序和大小完全相同,所以可以强转

  1. 请解释大端序、小端序、网络字节序,并说明为何需要网络字节序

    小端序是把高位字节存储到高位地址上;大端序是把高位字节存储到低位地址上。因为保存栈的方式有差异,所以对网络传输数据的过程制定了标准,这就是“网路字节序”。而且,在网络字节序中,数据传输的标准是“大端序”

  2. 大端计算机希望将4字节整型数据12传到小端序计算机。请说出数据传输过程中发生的字节序变换过程

    因为网络字节序的顺序标准是“大端序”,所以大端序的计算机在网络传输中不需要先转换字节顺序,直接传输。但是接受数据的是小端序计算机,因此,要经过网络转本地序的过程,再保存到存储设备上

  3. 怎么表示回送地址?其含义是什么?如果向回送地址传输数据将会发生什么情况?

    回送地址表示计算机本身,为127.0.0.1。因此,如果将数据传送到IP地址127.0.0.1,数据会不会通过传输到网络的其他设备上而直接返回。

第四章 基于TCP的服务器端/客户端(1)

  1. 请说明TCP/IP的4层协议栈,并说明TCP和UDP套接字经过的层级结构差异

    链路层—>IP层—>TCP层—>应用层

    链路层—>IP层—>UDP层—>应用层

  2. 请说出TCP/IP协议栈中链路层和IP层的作用,并给出两者关系。

    链路层是LAN、WAN、MAN等网络标准相关的协议栈,是定义物理性质标准的层级。相反,IP层是定义网络传输数据标准的层级。即IP层负责以链路层为基础的数据传输

  3. 为何需要把TCP/IP协议栈分成4层(或7层)?结合开放式系统回答

    将复杂的TCP/IP协议分层化的话,就可以将分层的层级标准发展成开放系统。实际上,TCP/IP是开放系统,各层级都被初始化,并以该标准为依据组成了互联网。因此,按照不同层级标准,硬件和软件可以相互替代,这种标准化是TCP/IP蓬勃发张的依据

  4. 客户端调用connect函数向服务器端发送连接请求。服务器端调用哪个函数后,客户端可以调用connect函数?

    listen函数,客户端才可以调用connect函数

  5. 什么时候创建连接请求等待队列?它有何作用?与accept有什么关系

    listen函数的调用创建了请求等待队列。它是存储客户端连接请求信息的空间。accept函数调用后,将从本地存储的连接请求信息取出,与客户端建立连接。

  6. 客户端中为何不需要调用bind函数分配地址?如果不调用bind函数,那何时、如何向套接字分配IP地址和端口号?

    客户端是请求连接的程序,不是一个接收连接的程序。所以,指导服务器的地址信息是更重要的因素,没有必要通过bind函数明确地分配地址信息。但是,要想和服务器通信,必须将自己的地址信息分配到套接字上,因此,在connect函数调用时,自动把IP地址和端口号输入到套接字上

  7. 改成迭代服务器端

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>void error_handling(char *message);int main(int argc, char *argv[])
{int serv_sock;int clnt_sock;struct sockaddr_in serv_addr;struct sockaddr_in clnt_addr;socklen_t clnt_addr_size;char message[]="Hello World!";if(argc!=2){printf("Usage : %s <port>\n", argv[0]);exit(1);}serv_sock=socket(PF_INET, SOCK_STREAM, 0);if(serv_sock == -1)error_handling("socket() error");memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family=AF_INET;serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);serv_addr.sin_port=htons(atoi(argv[1]));if( bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr))==-1 )error_handling("bind() error"); if( listen(serv_sock, 5)==-1 )error_handling("listen() error");clnt_addr_size=sizeof(clnt_addr);  while(1){clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size);if(clnt_sock==-1)break;  write(clnt_sock, message, sizeof(message));close(clnt_sock);}close(serv_sock);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}

第五章 基于TCP的服务器端/客户端(2)

  1. 请说明TCP套接字连接设置的三次握手过程。尤其是3次数据交换过程每次收发的数据内容。

    网上有很多,就不一一写了

  2. TCP是可靠的数据传输协议,但在通过网络通信的过程可能丢失数据。请通过ACK和SEQ说明TCP通过何种机制保证丢失数据的可靠传输。

    SEQ顺序标识符是给信息编号。ACK是用于回复带有编号的信息。也就是说,每次传输信息时,都同时发送SEQ标识,而受到信息的主机应以SEQ信息为基础回复发送信息的主机。通过这种机制,传输数据的主机就可以确认数据是否被正确接收。在传输失败时,可以重新传送。

  3. TCP套接字中调用write和read函数时数据如何移动?结合I/O缓冲进行说明

    当write函数被调用时,数据就会向端口的输出缓冲区移动。然后经过网络传输传输到对方主机套接字的输入缓冲。这样,输入缓冲中存储的数据通过read函数的响应来读取

  4. 对方主机的输入缓冲剩余50字节空间时,若本方主机通过write函数请求传输70字节,问TCP如何处理这种情况?

    对方主机会把输入缓冲中可存储的数据大小传送给要传输数据的数据(本方)。因此,在剩余空间为50字节的情况,即使要求传送70字节的数据,也不能传输50字节以上,剩余的部分保存在传输方的输出缓冲中,等待对方主机的输入缓冲出现空间。而且,这种交换缓冲多余空间信息的协议被称为滑动窗口协议

  5. 更改程序,使服务器端和客户端各传送1次字符串…

/**********************************sendrecv_serv.c***********************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>void error_handling(char *message);int main(int argc, char *argv[])
{int serv_sock;int clnt_sock;int str_len, i;struct sockaddr_in serv_addr;struct sockaddr_in clnt_addr;socklen_t clnt_addr_size;char msg1[]="Hello client!";char msg2[]="I'm server.";char msg3[]="Nice to meet you.";char* str_arr[]={msg1, msg2, msg3};char read_buf[100];if(argc!=2){printf("Usage : %s <port>\n", argv[0]);exit(1);}serv_sock=socket(PF_INET, SOCK_STREAM, 0);if(serv_sock == -1)error_handling("socket() error");memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family=AF_INET;serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);serv_addr.sin_port=htons(atoi(argv[1]));if(bind(serv_sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1)error_handling("bind() error"); if(listen(serv_sock, 5)==-1)error_handling("listen() error");clnt_addr_size=sizeof(clnt_addr);  clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size);if(clnt_sock==-1)error_handling("accept() error");  for(i=0; i<3; i++){str_len=strlen(str_arr[i])+1;write(clnt_sock, (char*)(&str_len), 4);write(clnt_sock, str_arr[i], str_len);read(clnt_sock, (char*)(&str_len), 4);read(clnt_sock, read_buf, str_len);puts(read_buf);}close(clnt_sock);close(serv_sock);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}/***************************************recvsend_clnt.c***************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>void error_handling(char *message);int main(int argc, char* argv[])
{int sock;struct sockaddr_in serv_addr;char msg1[]="Hello server!";char msg2[]="I'm client.";char msg3[]="Nice to meet you too!";char* str_arr[]={msg1, msg2, msg3};char read_buf[100];int str_len, i;if(argc!=3){printf("Usage : %s <IP> <port>\n", argv[0]);exit(1);}sock=socket(PF_INET, SOCK_STREAM, 0);if(sock == -1)error_handling("socket() error");memset(&serv_addr, 0, sizeof(serv_addr));serv_addr.sin_family=AF_INET;serv_addr.sin_addr.s_addr=inet_addr(argv[1]);serv_addr.sin_port=htons(atoi(argv[2]));if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1) error_handling("connect() error!");for(i=0; i<3; i++){read(sock, (char*)(&str_len), 4);read(sock, read_buf, str_len);puts(read_buf);str_len=strlen(str_arr[i])+1;write(sock, (char*)(&str_len), 4);write(sock, str_arr[i], str_len);}close(sock);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}
  1. 创建收发文件的服务器端/客户端
/**********************************file_serv.c***********************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 30
void error_handling(char *message);int main(int argc, char *argv[])
{int serv_sd, clnt_sd;FILE * fp;char buf[BUF_SIZE];char file_name[BUF_SIZE];int read_cnt;struct sockaddr_in serv_adr, clnt_adr;socklen_t clnt_adr_sz;if(argc!=2) {printf("Usage: %s <port>\n", argv[0]);exit(1);}serv_sd=socket(PF_INET, SOCK_STREAM, 0);   memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=htonl(INADDR_ANY);serv_adr.sin_port=htons(atoi(argv[1]));bind(serv_sd, (struct sockaddr*)&serv_adr, sizeof(serv_adr));listen(serv_sd, 5);clnt_adr_sz=sizeof(clnt_adr);    clnt_sd=accept(serv_sd, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);read(clnt_sd, file_name, BUF_SIZE);fp=fopen(file_name, "rb");if(fp!=NULL){while(1){read_cnt=fread((void*)buf, 1, BUF_SIZE, fp);if(read_cnt<BUF_SIZE){write(clnt_sd, buf, read_cnt);break;}write(clnt_sd, buf, BUF_SIZE);}}fclose(fp);close(clnt_sd); close(serv_sd);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}/***************************************recvsend_clnt.c***************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>#define BUF_SIZE 30
void error_handling(char *message);int main(int argc, char *argv[])
{int sd;FILE *fp;char buf[BUF_SIZE];char file_name[BUF_SIZE];int read_cnt;struct sockaddr_in serv_adr;if(argc!=3) {printf("Usage: %s <IP> <port>\n", argv[0]);exit(1);}printf("Input file name: ");scanf("%s", file_name);fp=fopen(file_name, "wb");sd=socket(PF_INET, SOCK_STREAM, 0);   memset(&serv_adr, 0, sizeof(serv_adr));serv_adr.sin_family=AF_INET;serv_adr.sin_addr.s_addr=inet_addr(argv[1]);serv_adr.sin_port=htons(atoi(argv[2]));connect(sd, (struct sockaddr*)&serv_adr, sizeof(serv_adr));write(sd, file_name, strlen(file_name)+1);    while((read_cnt=read(sd, buf, BUF_SIZE))!=0)fwrite((void*)buf, 1, read_cnt, fp);fclose(fp);close(sd);return 0;
}void error_handling(char *message)
{fputs(message, stderr);fputc('\n', stderr);exit(1);
}

《TCP/IP网络编程》课后练习答案第一部分1~5章 尹圣雨相关推荐

  1. 《TCPIP网络编程》课后练习答案第一部分1~5章 尹圣雨

    第一章 理解网络编程和套接字 套接字在网络编程中的作用是什么?为什么称它为套接字? P2,网络编程就是编写程序让两台联网的计算机相互交换数据.在我们不需要考虑物理连接的情况下,我们只需要考虑如何编写传 ...

  2. 《TCP/IP网络编程》课后练习答案第一部分6~10章 尹圣雨

    第六章 基于UDP的服务器端/客户端 UDP为什么比TCP速度快?为什么TCP数据传输可靠而UDP数据传输不可靠? UDP和TCP不同,不进行流量控制.由于该控制涉及到套接字的连接和结束,以及整个数据 ...

  3. 高等学校计算机科学与技术教材:tcp/ip网络编程技术基础,TCP/IP网络编程技术基础...

    TCP/IP网络编程技术基础 语音 编辑 锁定 讨论 上传视频 <TCP/IP网络编程技术基础>是2012年北京交通大学出版社出版的图书,作者是王雷. 书    名 TCP/IP网络编程技 ...

  4. TCP/IP网络编程之多进程服务端(一)

    TCP/IP网络编程之多进程服务端(一) 进程概念及应用 我们知道,监听套接字会有一个等待队列,里面存放着不同客户端的连接请求,如果有一百个客户端,每个客户端的请求处理是0.5s,第一个客户端当然不会 ...

  5. TCP/IP网络编程之多进程服务端(二)

    TCP/IP网络编程之多进程服务端(二) 信号处理 本章接上一章TCP/IP网络编程之多进程服务端(一),在上一章中,我们介绍了进程的创建和销毁,以及如何销毁僵尸进程.前面我们讲过,waitpid是非 ...

  6. TCP/IP网络编程:P1->理解网络编程和套接字

    本系列文章为<TCP/IP网络编程----尹圣雨>学习笔记 文章目录 一.理解网络编程和套接字 1.1 构建接电话套接字 1.2 编写"Hello world!"服务器 ...

  7. TCP/IP网络编程:P3->地址族与数据序列

    本系列文章为<TCP/IP网络编程----尹圣雨>学习笔记,前面的系列文章链接如下 TCP/IP网络编程:P1->理解网络编程和套接字 TCP/IP网络编程:P2->套接字类型 ...

  8. TCP/IP网络编程之基于TCP的服务端/客户端(二)

    回声客户端问题 上一章TCP/IP网络编程之基于TCP的服务端/客户端(一)中,我们解释了回声客户端所存在的问题,那么单单是客户端的问题,服务端没有任何问题?是的,服务端没有问题,现在先让我们回顾下服 ...

  9. TCP/IP网络编程(1)

    1. 套接字 套接字是由操作系统提供的网络数据通信软件设备,即使对网络数据传输原理不了解,也能够使用套接字完成网络数据传输.为了与远程计算机进行数据传输,需要连接到英特网,套接字就是进行网络连接的工具 ...

最新文章

  1. 不愧是摸鱼高手Python matplotlib 绘制频谱图都会,能怪老板不管
  2. 将数据库服务器的文件D 改名为,MySQL如何更改数据库数据存储目录详解
  3. 计算机系统优化的目的和原理,优化原理
  4. Windows 7 镜像制作过程
  5. 读书笔记011:《伤寒论》- 手厥阴心包经
  6. HTML5新特性基础学习笔记下
  7. JAVA Swing 事件监听
  8. 问号后面能加感叹号吗_TOPIK|你还在因为不会用原稿纸而扣分吗
  9. Java多线程之可见性之volatile
  10. 解决ASP.NET页面回车回发的问题
  11. python学习笔记爬虫——爬取网络表情包
  12. 代码行数统计工具loc与iloc
  13. 【实验室顾问】俞扬教授 (CCF-IEEE CS青年科学家奖获得者)
  14. C语言中关于二级指针的笔试题
  15. 【Python计算机视觉】图像到图像的映射(单应性变换、图像扭曲)
  16. boost - 智能指针介绍
  17. 数据库---[复习2]---数据查询---设有一个SPJ数据库,包括S、P、J及SPJ4个关系模式··· ···
  18. python可以自动拆分表格吗_如何利用Python一键拆分表格并进行邮件发送~
  19. Java为 pdf、word和excel添加水印
  20. 如何实时计算日累计逐单资金流

热门文章

  1. 断舍离-你之所以无法放手的原因
  2. vmware下载和ubutun镜像下载以及火狐浏览器更新安装
  3. wow服务器显示锦标赛,魔兽世界史诗钥石地下城 全球锦标赛“计时赛”指南
  4. 如何打开vcf.gz文件
  5. Tomcat启动报错“java.lang.ClassNotFoundException: org.apache.catalina.loader.DevLoader”
  6. 这篇文章适合所有Android手机第一次买Android手机的可以看看!(ZT)
  7. Xamarin.Forsm for Android 系统功能
  8. 微信企业号/企业微信的corpid和secret
  9. nginx装逼语录待补充
  10. 分布式ID解决方案(一)数据库号段方式