翔翔の据点

Arrogance is the only obstacle to survival. Not weakness or ignorance.

0%

类加载

一个Java文件从编码完成到最终执行,一般主要包括两个过程

  • javac:将java源文件编译为.class字节码文件(javac是把你写的java代码编译成计算机能识别的内部代码)
  • java:把编译声称的.class文件交给Java虚拟机(JVM)执行(JVM初始化、加载.class、执行main())

而我们所说的类加载过程即是指JVM虚拟机把.class文件中类信息加载进内存,并进行解析生成对应的class对象的过程

举个通俗点的例子来说,JVM在执行某段代码时,遇到了class A, 然而此时内存中并没有class A的相关信息,于是JVM就会到相应的class文件中去寻找class A的类信息,并加载进内存中,这就是我们所说的类加载过程。

由此可见,JVM不是一开始就把所有的类都加载进内存中,而是只有第一次遇到某个需要运行的类时才会加载,且只加载一次

阅读全文 »

类与对象

类的基本概念

  • Java把类内的数据成员称为 域(field),封装于类内的函数称为方法(method)
    • main()也是方法
  • “类”就是把事物的数据与相关功能封装(Encapsulate)在一起,形成一种特殊的数据结构
阅读全文 »

n大多数网络应用系统可分为两个部分:客户端©和服务器端(S) 。

一个server经常同时和多个client建立连接

image-20200426101748109

image-20200426101803094

TCP 套接字通信工作流程

面向连接的套接字Socket通信工作流程

为了实现服务器与客户机的通信,服务器和客户机都必须建立套接字。服务器与客户机的工作原理可以用下面的过程来描述。

1.服务器先用 socket 函数来建立一个套接字,用这个套接字完成通信的监听

2.用 bind 函数来绑定一个端口号和 IP 地址。因为本地计算机可能有多个网址和 IP,每一个 IP 和端口有多个端口。需要指定一个 IP 和端口进行监听。

3.服务器调用 listen 函数,使服务器的这个端口和 IP 处于监听状态,等待客户机的连接。

4.客户机用 socket 函数建立一个套接字,设定远程 IP 和端口。

5.客户机调用 connect 函数连接远程计算机指定的端口。

6.服务器用 accept 函数来接受远程计算机的连接,建立起与客户机之间的通信。

7.建立连接以后,客户机用 write 函数向 socket 中写入数据。也可以用 read 函数读取服务器发送来的数据。

8.服务器用 read 函数读取客户机发送来的数据,也可以用 write 函数来发送数据。

9.完成通信以后,用 close 函数关闭 socket 连接。

基础概念

socket套接口

套接口是应用层到传输层的接口;类似于Unix管道,可以向/从“套接口”中写/读数据

sockfd套接字

套接口的描述字

报文格式

封装过程

image-20200426113810817

TCP报文格式

image-20200426113855858

img

其中比较重要的字段有:

注意区分两个ACK:ACK确认Ack是否有效(大写的单词表示标志位)

(1)序号(sequence number):Seq序号,占32位

TCP连接中传送的字节流中的每个字节都按顺序编号,第一个字节的编号由本地随机产生

seq其实就是这个报文段中的第一个字节的数据编号。

例如,一段报文的seq字段值是 200 ,而携带的数据共有100字节,显然下一个报文段(如果还有的话)的数据序号应该从300开始;

(2)确认号(acknowledgement number):Ack序号,占32位

只有ACK标志位为1时,确认序号字段才有效

Ack=Seq+1。期待收到对方下一个报文段的seq(第一个数据字节的序号);序列号表示报文段携带数据的第一个字节的编号;而确认号指的是期望接收到下一个字节的编号;因此当前报文段最后一个字节的编号+1即为确认号。

(3)==标志位(Flags)==:共6个,即URG、ACK、PSH、RST、SYN、FIN等。具体含义如下:

  • URG:紧急指针(urgent pointer)有效。
  • ACK:确认序号有效。占1位,仅当ACK=1时,确认号字段才有效。ACK=0时,确认号无效
  • PSH:接收方应该尽快将这个报文交给应用层。
  • RST:重置连接。
  • SYN:发起一个新连接。
  • FIN:释放一个连接。

状态转换图

==实线:client==的正常状态转换

==虚线:server==的正常状态转换

app:应用???

image-20200426104739547

TCP连接的建立(三次握手)

在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。

SYN:同步序列编号(Synchronize Sequence Numbers)。是TCP/IP建立连接时使用的握手信号。

为什么需要三次握手

首先非常明确的是两次握手是最基本的。第一次握手,客户端发了个连接请求消息到服务端,服务端收到信息后知道自己与客户端是可以连接成功的,但此时客户端并不知道服务端是否已经接收到了它的请求,所以服务端接收到消息后的应答,客户端得到服务端的反馈后,才确定自己与服务端是可以连接上的,这就是第二次握手。

客户端只有确定了自己能与服务端连接上才能开始发数据。所以两次握手肯定是最基本的。

看到这里,你或许会问,那么为什么需要第三次握手呢?我们来看一下,假设一下如果没有第三次握手,而是两次握手后我们就认为连接成功了,那么会发生什么?

第三次握手是为了防止已经失效的连接请求报文段突然又传到服务端,因而产生错误

譬如发起请求遇到类似这样的情况:客户端发出去的第一个连接请求由于某些原因在网络节点中滞留了导致延迟,直到连接释放的某个时间点才到达服务端,这是一个早已失效的报文,但是此时服务端仍然认为这是客户端的建立连接请求第一次握手,于是服务端回应了客户端,第二次握手。

如果只有两次握手,那么到这里,连接就建立了,但是此时客户端并没有任何数据要发送,而服务端还在傻傻的等候佳音,造成很大的资源浪费。所以需要第三次握手,只有客户端再次回应一下,就可以避免这种情况。

三次握手过程

image-20200426105615672

服务器必须准备好接受外来的连接。这通过调用socket、 bind和listen函数来完成,称为被动打开(passive open)。

第一次握手:客户通过调用connect进行主动打开(active open)。这引起客户TCP发送一个SYN(表示同步)分节(SYN=J),它告诉服务器客户将在连接中发送到数据的初始序列号。并进入SYN_SEND状态,等待服务器的确认。

第二次握手:服务器必须确认客户的SYN,同时自己也得发送一个SYN分节,它含有服务器将在同一连接中发送的数据的初始序列号。服务器以单个字节向客户发送SYN和对客户SYN的ACK(表示确认),此时服务器进入SYN_RECV状态。

第三次握手:客户收到服务器的SYN+ACK。向服务器发送确认分节,此分节发送完毕,客户服务器进入ESTABLISHED状态,完成三次握手。

客户端的初始序列号为J,而服务器的初始序列号为K。在ACK里的确认号为发送这个ACK的一端所期待的下一个序列号。因为SYN只占一个字节的序列号空间,所以每一个SYN的ACK中的确认号都是相应的初始序列号加1.类似地,每一个**FIN(表示结束)**的ACK中的确认号为FIN的序列号加1.

TCP连接的终止

image-20200426104628587

Step 1.应用首先调用close,主动关闭,发送一个FIN,表示数据发送完毕。

Step 2.另一端执行被动关闭,FIN由TCP确认,接收也作为文件结束符传递给接收方,在此连接上再也收不到数据

Step 3.收到文件结束的应用将调用close关闭它的套接口,它的TCP也发送一个FIN。

Step 4.接收到这个FIN的发送方TCP对之确认。

图中是客户执行主动关闭,而实际上,不管客户还是服务器都可以执行主动关闭,通常是由客户主动关闭,然而,如HTTP是客户端/服务器执行主动关闭?

第一次握手:某个应用进程首先调用close,我们称这一端执行主动关闭。这一端的TCP于是发送一个FIN分节,表示数据发送完毕。

第二次握手:接收到FIN的另一端执行被动关闭(passive close)。这个FIN由TCP确认。它的接收也作为文件结束符传递给接收端应用进程(放在已排队等候应用进程接收到任何其他数据之后)

第三次握手:一段时间后,接收到文件结束符的应用进程将调用close关闭它的套接口。这导致它的TCP也发送一个FIN。

第四次握手:接收到这个FIN的原发送端TCP对它进行确认。

面向字节的数据传送流(如TCP字节流、Unix管道等)也使用EOF表示在某个方向上不再有数据待传送。在TCP字节流中,EOF的读或写通过收发一个特殊的FIN分节来实现。

image-20200426105449109

如何计算时延,抖动???时延一会小一会大

datetimes.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/****************************************************/
/************* datetime Example Server **************/
/****************************************************/

#include "datetime.h"
// #include <sys/time.h>

int main(int argc, char **argv)
{
int listenfd, connfd; // file discripter
struct sockaddr_in servaddr;
char buff[MAXLINE];
time_t ticks;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(50000);
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
listen(listenfd, 1024);
char* str = "Start listening";
printf("%s\n", str);
// fflush(stdout); // printf如果没有换行符,则不会立即输出,需要调用fflush
for (;;)
{
connfd = accept(listenfd, (struct sockaddr *)NULL, NULL);
ticks = time(NULL);
printf("client: %s:%d\n",servaddr.sin_addr,servaddr.sin_port);
snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
write(connfd, buff, strlen(buff));
close(connfd);
}
}

相关函数

不清楚的概念

TCP/IP

FTP/Telnet

API

网络编程API有两种:sockets和XTI???

协议族

1
2