网络编程
一、网络编程概述
1.计算机网络
把分布在不同地理区域的具有独立功能的计算机,通过通信设备,网线连接起来,实现在不同的计算机之间资源共享,信息互通。
2.网络编程(语言)
- 我们所编写的程序具备在网络间进行信息传递的,java是支持网络通信。
- 将底层实现细节封装起来。
网络编程的目的:
直接或间接地通过网络协议与其它计算机进行通讯
3.网络通信
两个主要问题:
- 如何找到计算机网络中的某台主机(IP)
- 找到主机后如何可靠安全高效数据传输(通信协议)
如何实现网络中的主机互相通信:
- 通信双方地址
- 一定的规则
二、通讯要素:IP+端口号
1.IP 地址:InetAddress
公网地址(万维网使用)和私有地址(局域网使用),(192.168开头的就是私有地址)
本地回环地址:本机的编号
开头的就是私有址址,范围即为192.168.0.0-192.168.255.255,专门为组织机构内部使用
特点:不易记忆
2.端口号
给计算机上运行的程序分配的编号—端口号(不重复)
不同的进程有不同的端口号
端口号与IP地址的组合得出一个网络套接字
三、 InetAddress类
DNS:域名解析服务器
1.表示地址的两种方式
Internet上的主机有两种方式表示地址:
域名(hostName):www.baidu.com
IP 地址(hostAddress):220.181.111.37
域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS)负责将域名转化成IP地址,这样才能和主机建立连接。 --域名解析
2.方法:
InetAddress. getByName("www.baidu.com");
getHostAddress();//获取IP地址
getHostName();//获取域名
四、通讯要素:网络通信协议
在通信过程中双方定义的一系列的规则(计算机网络中实现通信必须有一些约定即通信协议,对速率、传输代码、代码结构传输控制步骤、出错控制等制定标准)
例如:传输的速率,代码,代码结构,出错控制
1.通讯协议的分层思想
由于结点之间联系很复杂,在制定协议时,把复杂成份分解成一些简单的成份,再将再将它们复合起来。
最常用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与再下一层不发生关系。各层互不影响,利于系统的开发和扩展.
2.传输控制协议TCP(Transmission Control Protocol)
- 面向连接:通信之前,要先建立连接 聊天 在不, 我在, 给你说个事
- 安全可靠
- 传输数据大
- 效率低
3.三次握手
使用TCP协议前,须先建立TCP连接,形成传输数据通道
传输前,采用“三次握手”方式,是可靠的
第一次握手:客户端—>服务器 服务器知道了客户端想建立联系
第二次握手: 服务器—>客户端 客户端知道服务器收到建立联系的请求了
第三次握手:客户端—>服务器 服务器知道了客户端收到了自己的回应
标志位(Flags):共6个,即URG、ACK、PSH、RST、SYN、FIN等,具体含义如下:
URG:紧急指针(urgent pointer)有效。
ACK:确认序号有效。
PSH:接收方应该尽快将这个报文交给应用层。
RST:重置连接。
SYN:发起一个新连接。
FIN:释放一个连接。
4.四次挥手
TCP协议进行通信的两个应用进程:客户端、服务端
传输完毕,需释放已建立的连接,效率低
在断开时要进行“四次挥手”
1, 客户端进程发出连接释放报文,并且停止发送数据。
2, 服务器收到连接释放报文,发出确认报文,
3.接受服务器发送的最终数据,客户端收到服务器的连接释放报文后,必须发出确认
4.服务器只要收到了客户端发出的确认,立即进入CLOSED状态
5.用户数据报协议UDP(User Datagram Protocol)。
- 将数据、源、目的封装成数据包,无连接 发射导弹 具体的位置输入到导弹
- 不安全
- 传输速度快
- 每个数据报的大小限制在64K内
- **基于****IP+**端口
举例:发短信,不需要双方建立连接,But,数据报的大小应限制在64k以内
五、Socket(套接字)
- 通信的两端都要有Socket,是两台机器间通信的端点
- 网络通信其实就是Socket间的通信
- Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输
一般主动发起通信的应用程序属客户端,等待通信请求的为服务端。
1.通信模型
2.客户端Socket的工作过程
包含以下四个基本的步骤:
- 创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。
- 打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输
- 按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入线路的信息),通过输出流将信息写入线程。
- 关闭 Socket:断开客户端到服务器的连接,释放线路
3.服务器程序的工作过程
包含以下四个基本的步骤:
- 调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求
- 调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象
- 调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出流和输入流,开始网络数据的发送和接收
- 关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字
4.通信1.0
实现客户端向服务器端发送消息,服务器端接收消息。
服务器:
public class Server {
//启动服务端程序
public static void main(String[] args) throws IOException {
//创建服务器
ServerSocket serverSocket = new ServerSocket(3333);
System.out.println("服务器创建成功,等待客户端连接中.....");
//监听有没有客户端连接到服务器,连接到后并返回客户端socket对象,如果一直没有客户端连接,一直阻塞等待
Socket socket =serverSocket.accept();
System.out.println("客户端已连接服务器");
//在服务器端接收客户端消息
InputStream in = socket.getInputStream();
byte[] b = new byte[100];
int length = in.read(b);//读取客户端发送内容到数组中,返回实际装入的长度
String as = new String(b, 0, length, "utf-8");
System.out.println(as);
}
}
客户端:
public class Client {
//启动客户端
public static void main(String[] args) throws IOException {
//创建客户端
Socket socket = new Socket("127.0.0.1",3333);//添加地址,端口号
//发送
OutputStream out = socket.getOutputStream();
out.write("你好我是客户端".getBytes("utf-8"));
}
}
5.通信2.0
实现客户端向服务器端发送消息,服务器端接收消息,并在服务器端向客户端返回一条消息,并在客户端打印输出。
服务器端:
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(3333);
System.out.println("服务器创建成功,等待客户端连接中.....");
Socket socket =serverSocket.accept();
System.out.println("客户端已连接服务器");
InputStream in = socket.getInputStream();
byte []b =new byte[100];
int length = in .read(b);
String as =new String(b,0,length,"utf-8");
System.out.println(as);
OutputStream out = socket.getOutputStream();
out.write("你好我是服务器".getBytes("utf-8"));
}
}
客户端:
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",3333);
OutputStream out = socket.getOutputStream();
out.write("你好我是客户端".getBytes("utf-8"));
InputStream in = socket.getInputStream();
byte []b =new byte[100];
int length = in .read(b);
String as =new String(b,0,length,"utf-8");
System.out.println(as);
}
}
6.通信3.0
在客户端和服务器端,引入Scanner在控制台输入信息,向对方发送。
服务器端:
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(3333);
System.out.println("服务器创建成功,等待客户端连接中.....");
Socket socket =serverSocket.accept();
System.out.println("客户端已连接服务器");
//接收
InputStream in = socket.getInputStream();
byte []b =new byte[100];
int length = in .read(b);
String as =new String(b,0,length,"utf-8");
System.out.println(as);
//发送
Scanner scanner = new Scanner(System.in);
System.out.println("服务器端:");
String s1 = scanner.nextLine();
OutputStream out = socket.getOutputStream();
out.write(s1.getBytes("utf-8"));
}
}
客户端:
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",3333);
//发送
Scanner scanner = new Scanner(System.in);
System.out.println("客户端:");
String s = scanner.nextLine();
OutputStream out = socket.getOutputStream();
out.write(s.getBytes("utf-8"));
//接收
InputStream in = socket.getInputStream();
byte []b =new byte[100];
int length = in .read(b);
String as =new String(b,0,length,"utf-8");
System.out.println(as);
}
}
7.通信4.0
尝试引入循环,在一个客户端和服务器之间进行多次消息发送。
服务器端:
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(3333);
System.out.println("服务器创建成功,等待客户端连接中.....");
Socket socket =serverSocket.accept();
System.out.println("客户端已连接服务器");
while (true){
//接收
InputStream in = socket.getInputStream();
byte[] b = new byte[100];
int length = in.read(b);
String as = new String(b, 0, length, "utf-8");
System.out.println(as);
if(as.equals("88")){
System.exit(1);
}
//发送
Scanner scanner = new Scanner(System.in);
System.out.println("服务器端:");
String s1 = scanner.nextLine();
OutputStream out = socket.getOutputStream();
out.write(s1.getBytes("utf-8"));
}
}
}
客户端:
public class Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",3333);
while (true){
//发送
Scanner scanner = new Scanner(System.in);
System.out.println("客户端:");
String s = scanner.nextLine();
OutputStream out = socket.getOutputStream();
out.write(s.getBytes("utf-8"));
if(s.equals("88")){
System.exit(1);
}
//接收
InputStream in = socket.getInputStream();
byte[] b = new byte[100];
int length = in.read(b);
String as = new String(b, 0, length, "utf-8");
System.out.println(as);
}
}
}
六、UDP网络通信
1.流程
- DatagramSocket与DatagramPacket实现了基于 UDP 协议网络程序
- 建立发送端,接收端
- 建立数据包
- 调用Socket的发送、接收方法
- 关闭Socket
发送端与接收端是两个独立的运行程序。
2.发送端
public class Client {
//启动客户端
public static void main(String[] args) throws IOException {
int i = 0;
DatagramSocket ds = new DatagramSocket();
while (true) {
String s = "你好服务器"+(++i);
byte[] b = s.getBytes("utf-8");
DatagramPacket dp = new DatagramPacket(b, b.length, InetAddress.getByName("192.168.31.127"), 9966);
ds.send(dp);
}
}
}
3.接收端
public class Server {
//启动服务端程序
public static void main(String[] args) throws IOException {
//创建服务器
DatagramSocket ds = new DatagramSocket(9966);
while (true) {
byte[] b = new byte[100];
DatagramPacket dp = new DatagramPacket(b, 0, b.length);
ds.receive(dp);
String s = new String(b, 0, dp.getLength(), "utf-8");
System.out.println(s);
}
}
}