目录
什么是网络编程?
含义:使用套接字来达到进程间通信。
最主要的工作:在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的。
网络编程三要素?
IP地址
IP地址可以唯一的标识网络中的设备,通过这个标识号来指定要接受数据的计算机和识别发送的计算机。
端口
端口号可以唯一标识设备中的应用程序,也就是应用程序的标识。
协议
位于同一网络中的计算机进行连接和通信时需要遵守一定的规则,如行驶的汽车遵守交通规则。
常见的协议有TCP协议和UDP协议。
IP地址的分类及常用的DOS命令?
IP地址分五类:
-
A类地址,是指在IP地址的四段号码中,第一段号码为网络号码,剩下的三段号码为本地计算机的号码;
地址范围1.0.0.1到127.255.255.254 (二进制表示为:00000001 00000000 00000000 00000001 - 01111111 11111111 11111111 11111110)。最后一个是广播地址。
-
B类地址,是指在IP地址的四段号码中,前两段号码为网络号码;
地址范围128.0.0.1-191.255.255.254(二进制表示为:10000000 00000000 00000000 00000001----10111111 11111111 11111111 11111110)。 最后一个是广播地址。
-
C类地址,是指在IP地址的四段号码中,前三段号码为网络号码,剩下的一段号码为本地计算机的号码;
地址范围192.0.0.1-223.255.255.254 (二进制表示为: 11000000 00000000 00000000 00000001 - 11011111 11111111 11111111 11111110)。
-
D类地址,其第一个字节以“1110”开始,是一个专门保留的地址;
多播地址的最高位必须是“1110”,范围从224.0.0.0到239.255.255.255。
-
E类地址,以“1111”开始;
他的第一字节的范围是240~255,为将来使用保留。其中240.0.0.0~255.255.255.254作为保留地址,255.255.255.255作为广播地址。
类 | 范围值 |
---|---|
A | 0~127 |
B | 128~191 |
C | 192~223 |
D | 224~239 |
E | 240~255 |
IP地址主流格式有两大类:
IPv4:IPv4协议规定,IP地址的长度为32位。这32位包括了网络号部分(netid)和主机号部分(hostid)。
IPv6:IPV6的16字节(128bit)地址采用如下记法:每2个字节一组,共分8组,每组采用16进制表示方法,组与组之间用冒号“:”隔开。
常用的DOS命令:
C:\Users\user>ipconfig//查看本机IP地址
C:\Users\user>ping IP地址//检查网络是否连通
端口的概念和相关DOS命令?
端口号: 用两个字节表示的整数,它的取值范围是0 - 65535。
-
公认端口:0 - 1023之间的端口号用于一些知名的网络服务和应用,比如80端口分配给www,21端口分配给FTP
-
注册端口:1024 - 49151 分配给用户进程或应用程序
-
动态/私有端口: 49152 - 65535
-
如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败
端口相关DOS命令:
C:\Users\user>netstat -ano//查看所有端口
C:\Users\user>netstat -ano|findstr "80"//查看指定端口
C:\Users\user>tasklist|findstr "12476"//查看指定进程
InetAddress的使用?
方便对IP地址的获取和操作。
InetAddress:此类表示Internet协议(IP)地址,用于封装计算机的IP地址和DNS(没有端口信息)。
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressTest {
public static void main(String[] args) throws UnknownHostException {
//确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址和域名
InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1");
InetAddress inetAddress2 = InetAddress.getByName("localhost");
InetAddress inetAddress3 = InetAddress.getByName("www.baidu.com");
String name = inetAddress2.getHostName();//获取此IP地址的主机名
String ip = inetAddress2.getHostAddress();//返回文本显示中的IP地址字符串
System.out.println(name+ip);
}
}
URL的概念与常用方法?
URL: Uniform Resource Locator 统一资源定位符。
URL格式:协议类型://服务器地址[:端口号]/路径/文件名[参数=值]。
协议(HTTP):规定数据传输的方式。
域名(IP):在网络环境中找到主机,用 :// 与协议分隔开。
端口(port):(常省略)在网络主机上,标识一个进程(应用程序),用 : 与域名分隔开。
资源路径(path):标识网络资源(文件,图片,音视频,变量...),用/ 与端口分隔开。
查询参数(parameter):传递给资源路径对应的数据,用 ? 与资源路径分隔开,查询内部参数用 & 分隔多个键值对。
锚点(anchor):从 “#” 开始到最后,都是锚部分(前端用以作页面定位)。
URL常用方法:
public class UrlTest {
public static void main(String[] args) throws MalformedURLException {
//URL(String spec):从 String表示形成一个 URL对象
URL url = new URL("http://localhost:8080/user/index.html?id=1&name=用户名");
URL url1 = new URL("http://localhost:8080/user/index.html#top");
System.out.println(url.getProtocol());//获取此 URL的协议名称
System.out.println(url.getPath());//获取此 URL的路径部分
System.out.println(url.getHost());//获取此 URL的主机名
System.out.println(url.getPort());//获取此 URL的端口号
System.out.println(url.getQuery());//查询字符串,获取参数
System.out.println(url.getRef());//获取锚点
}
}
什么是协议?
计算机网络中,连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。
什么是TCP/IP协议?
TCP/IP协议: 传输控制协议/因特网互联协议( Transmission Control Protocol/Internet Protocol),是Internet最基本、最广泛的协议。
TCP/IP 是互联网相关各类协议族的总称。
TCP/IP协议的层次结构?
-
物理层:负责 比特流在节点之间的传输,即负责物理传输,这一层的协议既与链路有关,也与传输的介质有关。
-
链路层:定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、网线提供的驱动。(由底层网络定义的协议)
-
网络层:是整个TCP/IP协议的核心,主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络。(ICMP、IGMP、IP、ARP、RARP)
-
传输层:使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议。
-
应用层:主要负责应用程序的协议。(HTTP、FTP、TETP、SMTP、SNMP、DNS)
两种常见的网络协议?
UDP | TCP | |
---|---|---|
可靠性 | 不可靠 | 可靠 |
连接性 | 无连接 | 面向连接 |
报文 | 面向报文 | 面向字节流 |
效率 | 传输效率高 | 传输效率低 |
安全性 | 数据不安全,缺乏校验 | 数据安全,有校验 |
传输速度 | 快 | 慢 |
UDP协议:
用户数据报协议(User Datagram Protocol)
UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。
简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
由于使用UDP协议消耗资源少,通信效率高,所以通常都会用于音频、视频和普通数据的传输。
常用的使用UDP协议包括:TFTP、SNMP、NFS、DNS、BOOTP。
例如视频会议通常采用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。
工作原理:
UDP的发送端:
-
创建发送端的Socket对象(DatagramSocket)。如果没有指定端口,发送到本地主机所有可用端口(不常用),这里可以采用指定端口构造方法 DatagramSocket(),DatagramSocket(int port)
-
创建数据,并把数据封装成DatagramPacket包裹,数据一定要转成字节数组,同时需要指定IP地址和端口
DatagramPacket(byte[] buf, int length, InetAddress address, int port)。
-
调用DatagraSocket对象的方法发送数据包裹 void send(DatagramPacket p)。
-
关闭发送端,释放资源 void close()
实例:
import java.io.IOException;
import java.net.*;
public class UDP_Client1 {
public static void main(String[] args) throws IOException {
//发送对象
DatagramSocket ds = new DatagramSocket();
//字节数组存放发送的数据
byte[] data = "hello".getBytes();
//目的地址
InetSocketAddress inetAddress = new InetSocketAddress("localhost",1234);
//发送包裹
DatagramPacket dp = new DatagramPacket(data,data.length,inetAddress);
//发送
ds.send(dp);
System.out.println("已发送");
//关闭发送对象
ds.close();
}
}
UDP的接收端:
-
创建接收端的Socket对象(DatagramSocket),指定端口 DatagramSocket(int port)。
-
准备容器,封装成DatagramPacket包裹,用于接收数据 DatagramPacket(byte[] buf, int length)。
-
调用DatagramSocket对象的方法,阻塞式接收包裹 void receive(DatagramPacket p)。
-
解析数据包,并把数据在控制台显示
byte[] getData() 和 int getLength()。
-
关闭接收端,释放资源
void close()
实例:
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.io.IOException;
public class UDP_Server1 {
public static void main(String[] args) throws IOException {
//接收对象,监听指定端口
DatagramSocket ds = new DatagramSocket(1234);
//字节数组
byte[] data = new byte[1024];
//接受包裹
DatagramPacket dp = new DatagramPacket(data,data.length);
//阻塞式接收
ds.receive(dp);
System.out.println("已接收");
//结果输出
String res = new String(data,0,dp.getLength());
System.out.println(res);
//关闭
ds.close();
}
}
需要先启动服务器接收,再启动客户端发送,运行结果如下:
TCP协议:
传输控制协议(Transmission Control Protocol)
TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。
在TCP连接中必须明确客户端与服务器端,由于客户端向服务器端发出连接请求,每次连接的创建都需要经过“三次握手”。
三次握手:
TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠。
-
第一次握手:建立连接。客户端发送连接请求报文段,并将syn(标记位)设置为1,Squence Number(数据包序号)(seq)为x,接下来等待服务端确认,客户端进入SYN_SENT状态(请求连接);
-
第二次握手:服务端收到客户端的 SYN 报文段,对 SYN 报文段进行确认,设置 ack(确认号)为 x+1(即seq+1 ; 同时自己还要发送 SYN 请求信息,将 SYN 设置为1, seq为 y。服务端将上述所有信息放到 SYN+ACK 报文段中,一并发送给客户端,此时服务器进入 SYN_RECV状态。
SYN_RECV是指,服务端被动打开后,接收到了客户端的SYN并且发送了ACK时的状态。再进一步接收到客户端的ACK就进入ESTABLISHED状态。
-
第三次握手:客户端收到服务端的 SYN+ACK(确认符) 报文段;然后将 ACK 设置为 y+1,向服务端发送ACK报文段,这个报文段发送完毕后,客户端和服务端都进入ESTABLISHED(连接成功)状态,完成TCP 的三次握手。
完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用非常广泛。例如上传文件、下载文件、浏览网页等。
四次挥手:
四次挥手即终止TCP连接,就是指断开一个TCP连接时,需要客户端和服务端总共发送4个包以确认连接的断开。
挥手请求可以是Client端,也可以是Server端发起的,我们假设是Client端发起:
-
第一次挥手: Client端发起挥手请求,向Server端发送标志位是FIN报文段,设置序列号seq,此时,Client端进入
FIN_WAIT_1
状态,这表示Client端没有数据要发送给Server端了。 -
第二次挥手:Server端收到了Client端发送的FIN报文段,向Client端返回一个标志位是ACK的报文段,ack设为seq加1,Client端进入
FIN_WAIT_2
状态,Server端告诉Client端,我确认并同意你的关闭请求。 -
第三次挥手: Server端向Client端发送标志位是FIN的报文段,请求关闭连接,同时Client端进入
LAST_ACK
状态。 -
第四次挥手 : Client端收到Server端发送的FIN报文段,向Server端发送标志位是ACK的报文段,然后Client端进入
TIME_WAIT
状态。Server端收到Client端的ACK报文段以后,就关闭连接。此时,Client端等待2MSL的时间后依然没有收到回复,则证明Server端已正常关闭,那好,Client端也可以关闭连接了。
工作原理:
TCP协议基于请求-响应模式,第一次主动发起的程序被称为客户端(Client)程序
第一次通讯中等待连接的程序被称为服务器端(Sercer)程序。
客户端:
-
创建Socket(String host, int port)对象
-
向服务器发送连接请求
-
向服务器发送服务请求
-
接受服务结果(服务响应)
-
关闭流和Socket对象
实例:
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
public class TCP_Client1 {
public static void main(String[] args) throws IOException {
//建立连接
Scanner sc = new Scanner(System.in);
Socket socket = new Socket("localhost",1122);
//输入要发送的内容
System.out.println("请输入要发送的内容");
String msg = sc.next();
//将字节流转为标准输出流
PrintWriter pw = new PrintWriter(socket.getOutputStream());
//将信息写入输出流中
pw.println(msg);
//关闭
pw.close();
socket.close();
System.out.println("发送成功");
}
}
服务器端:
-
创建ServerSocket(int port)对象
-
在Socket上使用accept方法监听客户端的连接请求
-
阻塞、等待连接的建立
-
接收并处理请求信息
-
将处理结果返回给客户端
-
关闭流和Socket对象
实例:
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TCP_Server1 {
public static void main(String[] args) throws IOException {
//监听指定端口
ServerSocket serverSocket = new ServerSocket(1122);
System.out.println("等待接收");
//获取
Socket socket = serverSocket.accept();
//将socket中的输入流转为带缓冲区的字符流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//一行一行读数据
String msg = br.readLine();
System.out.println(msg);
//关闭
br.close();
socket.close();
serverSocket.close();
}
}
需要先启动服务器接收,再启动客户端发送,运行结果如下: