文章目录
1. Socket
客户端和服务器端在通信前,双方都要建立一个套接字,然后再将套接字连接起来形成管道,进行数据传输。
在创建 Socket
时,需要指定是 IPv4
还是 IPv6
,分别对应设置为 AF_INET 和 AF_INET6
;是 TCP
还是 UDP
,分别对应设置为 SOCK_STREAM
和 SOCK_DGRAM
。创建完成后,会返回一个描述符。
- 描述符:用来在一台计算机内部识别套接字的机制;
- 端口号:用来让通信的另一方能识别出套接字的机制;
1.1 基于 TCP 协议
1.1.1 服务器端
- 首先服务端调用
socket()
函数创建一个socket
描述符,参数中指定协议族、sokcet 类型、协议,唯一标识一个 socket,后续操作都有用到它; - 然后调用
bind
函数,参数中指定 socket 描述符、地址、socket 长度,将相应的地址和端口赋给 socket,也就是和 socket 相绑定。 - 然后调用
listen
函数将 socket 变为被动的连接监听的 socket,参数中指定 socket 描述符、该 socket 可以排队的最大连接数。因为 socket 函数返回的 socket 默认都是主动连接的 socket,所以在服务端需将它转为被动等待连接的 socket; - 而 accept 函数位于 listen 函数后,默认会阻塞进程,直到有一个客户端请求连接;
- 实现类是ServerSocket。
package CommunicationDemo;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
//模拟服务端
public class TcpServerDemo2 {
public static void main(String[] args) throws Exception {
//1.创建服务
ServerSocket serverSocket = new ServerSocket(9000);
//2.监听客户端连接 //阻塞式
Socket socket = serverSocket.accept();
//3.获取输入流
InputStream is = socket.getInputStream();
//4.文件输出
FileOutputStream file = new FileOutputStream(new File(""));
byte[] bytes = new byte[1024];
int len;
while((len=is.read(bytes))!=-1){
file.write(bytes,0,len);
}
//通知客户端接收完毕
OutputStream os = socket.getOutputStream();
os.write("接收完毕".getBytes());
//关闭资源
file.close();
is.close();
socket.close();
serverSocket.close();
}
}
1.1.2 客户端
-
指定远程服务器的ip地址和端口创建socket实例
- 调用
connect
函数主动连接服务器,通过三次握手建立连接。连接过程不是由 connect 函数完成,它仅仅是通知 linux 内核,让 linux 内核自动完成 TCP 三次握手连接;通常 connect 默认会一直阻塞,直到三次握手成功或失败; - 服务端 accept 接收到请求后,就建立连接,然后会返回一个新的 socket原来的 socket 则继续监听其他客户端的连接请求。
- 调用
-
通过socket实例获取输出流和输出流进行数据的读写
-
数据传输完毕,调用socket的close方法关闭连接
package CommunicationDemo;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
//模拟客户端下载文件
public class TcpClientDemo2 {
public static void main(String[] args) throws Exception {
//1.建立连接
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);
//2.创建输出流
OutputStream os = socket.getOutputStream();
//3.读取文件变成流
FileInputStream file = new FileInputStream(new File(""));
//4.写出文件流
byte[] buffer = new byte[1024];
int len;
while((len=file.read(buffer))!=-1){
os.write(buffer,0,len);
}
//通知服务器结束了
socket.shutdownOutput();
//确定服务端接受完毕
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer2 = new byte[1024];
int len2;
while((len2=is.read(buffer2))!=-1){
baos.write(buffer2,0,len2);
}
System.out.println(baos.toString());
//断开连接
baos.close();
is.close();
file.close();
os.close();
socket.close();
}
}
1.2 基于 UDP 协议
由于 UDP
没有连接,不需要三次握手,也就不需要 listen
和 connect
函数,但是 UDP
仍然需要 IP
地址和端口,因而需要 bind
函数。
UDP
没有维护连接状态,因而只需要一个 Socket
,就能和多个客户端进行通信。
1.2.1 服务端
- 指定本地端口创建DatagramSocket实例
- 通过字节数组创建DatagramSocket实例,调用其receive方法来接受数据
- 设置实例返回的数据、调用send方法发送
- 传输完成关闭连接
package CommunicationDemo.UDPDemo;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
//接收端
public class UdpServerDemo01 {
public static void main(String[] args) throws Exception {
//开放端口
DatagramSocket socket = new DatagramSocket(9090);
//接收数据包
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);
socket.receive(packet);
System.out.println(packet.getAddress().getHostAddress());
System.out.println(new String(packet.getData(),0, packet.getLength()));
socket.close();
}
}
1.2.2 客户端
- 创建实例
- 通过ip和端口发送数据包
- 通过字节数组创建实例receive方法接受数据包
- 传输完成关闭连接
package CommunicationDemo.UDPDemo;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
//发送端
public class UdpClientDemo01 {
public static void main(String[] args) throws Exception {
//1.建立socket
DatagramSocket socket = new DatagramSocket();
//2.建立包
String msg = "你好,服务器";
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length,InetAddress.getByName("localhost"),9090);
//3.发送包
socket.send(packet);
//4.关闭流
socket.close();
}
}
2. DNS 协议
用户与互联网上的主机通信时,需要将域名解析为 IP
地址,它需要由分布在互联网上的许多 DNS
服务器共同完成。
客户端在查询 IP
地址时,查询消息包含三种信息:
- 域名:
Web
服务器、邮件服务器的名称; Class
:用来识别网络,但一般Class
的值都是代表互联网的IN
;- 记录类型:表示域名对应何种类型的记录。例如,类型 A 表示域名对应的是 IP 地址;类型 MX 表示域名对应的是邮件服务器;类型 CNAME 表示域名对应的是相关别名等。
DNS
服务器中的信息都按照域名分层次进行保存,域名中越靠后的位置表示其层级越高。将管理下一级域的 DNS
服务器的 IP
地址注册到它们的上级服务器中,以此类推。这样就可以通过上级 DNS
服务器查询出下级 DNS
服务器的 IP
地址。所以,对于任意一个域的 DNS
服务器,都可以从根域开始依次找到。
域名服务器按照作用可划分四个类型:
- 根域名服务器:最高层级的域名服务器,管理着
com
、cn
、net
等顶级域名服务器的信息。根域名服务器信息会保存在互联网中所有的DNS
服务器中。 - 顶级域名服务器:管理在该顶级域名服务器注册的所有二级域名。
- 权限域名服务器:它是负责一个区的域名服务器。
- 本地域名服务器:当主机发出
DNS
查询请求时,查询请求首先会发送给本地域名服务器。
当应用进程需要把域名解析为 IP
地址时,该应用进程就调用解析程序,并成为 DNS
的一个客户,把待解析的域名放在 DNS
请求报文中,以用户数据报方式发送给本地域名服务器。本地域名服务器在查找到域名后,把对应的 IP
地址放在响应报文中。应用进程获取目的主机的 IP
地址即可进行通信。
域名解析的查询步骤如下:
- 主机先向本地域名服务器发出
DNS
请求,进行递归查询; - 如果能找到对应的
IP
地址,就直接返回;否则就采用递归查询,先向根域名服务器进行迭代查询; - 根域名服务器告诉本地域名服务器,下一步应该查询的顶级域名服务器的
IP
地址; - 本地域名服务器向顶级域名服务器进行查询;
- 顶级域名服务器告诉本地域名服务器,下一步应该查询的权威域名服务器的
IP
地址; - 本地域名服务器向权威域名服务器进行查询;
- 权威域名服务器告诉本地域名服务器,所查询的主机的
IP
地址; - 本地域名服务器把查询结果返回给主机。
此外,有时并不需要从根域名服务器开始查询,因为 DNS 服务器中设置缓存保存了之前查询过的域名。如果要查询的域名已经在缓存中,就可以直接得到所需信息,接下来从缓存的位置开始向下进行。
2.1 使用的协议
在 DNS 系统中,有两种类型的 DNS 服务器,分别为主 DNS 服务器和辅助 DNS 服务器。
- 在一个区中主 DNS 服务器从自己本机的数据文件中读取该区的 DNS 数据信息;
- 而辅助 DNS 服务器则从区的主 DNS 服务器中读取该区的 DNS 数据信息。当一个辅助 DNS 服务器启动时,它需要与主 DNS 服务器通信,并加载数据信息,这就叫做区传送。
区域传送
区域传送时使用 TCP 协议,主要有以下两点考虑:
- 辅域名服务器会定时(一般是 3 小时)向主域名服务器进行查询,看数据是否有变动。如有变动,则会执行一次区域传送,进行数据同步。区域传送将使用 TCP,这是因为数据同步传送的数据量比较大,远超过 512 字节。
- 另外由于 TCP 是一种提供可靠服务的连接,保证了数据的准确性。
域名解析
域名解析时使用== UDP== 协议:
- 客户端向 DNS 服务器查询域名时,一般返回的内容都不超过 512 字节,用 UDP 传输即可。不用经过 TCP 三次握手,这样 DNS 服务器负载更低,响应更快。
3. FTP 协议
FTP
是使用最广泛的文件传送协议,使用 TCP
可靠的运输服务,减少或消除不同操作系统下处理文件的不兼容性。
它使用客户服务器方式。一个服务器进程可同时为多个客户进程服务。可由两个部分组成:
- 主进程,负责接受新的请求;
- 若干个从属进程,负责处理单个请求。
主进程的工作步骤:
- 服务器打开
21
号端口,等待客户进程发出连接请求; - 收到连接请求后,启动从属进程进行处理。从属进程对客户进程的请求处理完毕后就会终止,但从属进程在运行期间根据需要还可能创建其他一些子进程;
- 处理后主进程又回到等待状态,继续接受其他客户进程发来的请求。
如上图,FTP
的客户端和服务器端之间要建立两个并行的 TCP
连接:
- 控制连接:控制连接会话期间一直保持打开,
FTP
客户发出的传送请求,通过控制连接发送给服务器端的控制进程; - 数据连接:实际用来传输文件的。
当客户进程向服务器进程发出建立连接请求时,要寻找连接服务器进程的 21
号端口,同时还要告诉服务器进程自己的另一个端口号码,用于建立数据传送连接。接着,服务器进程用自己传送数据的 20
号端口与客户进程提供的端口号建立数据传达连接。
4. SMTP/POP3
SMTP 是简单的邮件传送协议,用于发送邮件。通常使用的是 25 端口。
POP3 与 SMTP 对应,用于接收邮件。通常使用的是 110 端口。