19 网络编程
19.1 计算机网络
计算机网络:指将地理不同的具有独立功能的多台计算机及外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
19.2 网络编程
实现多台计算机之间实现数据的共享和传递。
网络应用程序主要组成为: 网络编程+IO流+多线程
19.3 网络模型
19.4 网络编程三要素
网络通讯的模型:请求-响应,客户端-服务端
三要素:IP地址,端口,协议(数据传输的规则)
19.4.1 IP地址
含义:
网络中计算机的唯一标识(IP地址是一个32位的二进制数据,为了方便,将一个字节的二进制转换为一个十进制的数据)
组成:
网络号段+主机段
分类:
A类IP地址:第一段号码为网络号码,剩下的三段号码为本地计算机的号码
----可以配置256* 256* 256台主机
B类IP地址:前二段号码为网络号码,剩下的二段号码为本地计算机的号码
C类地址前三段号码为网络号码,剩下的一段号码为本地计算机的号码
拓展:
A类地址的表示范围为:0.0.0.0~126.255.255.255,默认网络屏蔽为:255.0.0.0;A类地址分配给规模特别大的网络使用。A类网络用第一组数字表示网络本身的地址,后面三组数字作为连接于网络上的主机的地址。分配给具有大量主机(直接个人用户)而局域网络个数较少的大型网络。例如IBM公司的网络。
B类地址的表示范围为:128.0.0.0~191.255.255.255,默认网络屏蔽为:255.255.0.0;
C类地址的表示范围为:,默认网络屏蔽为:;类地址分配给小型网络,如一般的局域网和校园网,它可连接的主机数量是最少的,采用把所属的用户分为若干的网段进行管理。
特殊地址:
127.0.0.1 回环地址,可用于测试本机的网络是否有问题( ping 127.0.0.1 )
查看本机IP( DOS命令 ipconfig )
xxx.xxx.xxx.255 广播地址
示例:获取本机的ip
//获取本机ip地址
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
示例:获取百度首页的ip
//获取百度首页服务器的ip地址
InetAddress byName = InetAddress.getByName("www.baidu.com");
System.out.println(byName);
//www.baidu.com/14.215.177.39
//获取百度首页服务器的所有ip
InetAddress[] allByName = InetAddress.getAllByName("www.baidu.com");
for (InetAddress inetAddress : allByName) {
System.out.println(inetAddress);
}
/*
www.baidu.com/14.215.177.39
www.baidu.com/14.215.177.38
*/
注:一个域名可以对应多个地址,但一个ip只能对应一个域名。
19.4.2 端口号
-
A:每个网络程序都会至少有一个逻辑端口
-
B:用于标识进程的逻辑地址,不同进程的标识不同
-
C:有效端口:065535,其中01024系统使用或保留端口。
a) 80
b) ftp:23
c) www.baidu.com:80
通过第三方工具可以查看
注:端口与协议有关:TCP和UDP的端口互不相干,同一个协议的端口不能重复,不同协议的可以重复
19.4.3 协议
通信规则,就是数据的传输规则
TCP、UDP都是传输层的协议
TCP
建立连接,形成传输数据的通道;在连接中进行大数据量传输;通过三次握手完成连接,是可靠协议;必须建立连接,效率会稍低,例如:打电话
UDP
将数据源和目的封装到数据包中,不需要建立连接;每个数据报的大小在限制在64k;因无连接,是不可靠协议;不需要建立连接,速度快:例如发短信
19.5 InetAddress类
含义:用来表示主机的信息
getLocalHost(); —获取本地主机ip
getByName(); — 在给定主机名的情况下确定主机的 IP 地址。
getAllByName(); —在给定主机名的情况下确定主机所有的 IP 地址。
示例见:19.4.1
19.6 Socket
含义:套接字,表示的是ip地址和端口号的组合。
网络编程主要就是指Socket编程,网络之间的通信其实就是Socket间的通信,数据就通过IO流在两个Socket间进行传递。
19.7 TCP编程
Socket(客户端的套接字),ServerSocket(服务端的套接字)
客户端(发送一个请求) 服务端(接收到这个请求,给予响应)
19.7.1 示例
示例1:一对一聊天-----客户端和服务端(多线程)
客户端和服务端接收信息的线程类:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
public class ReceiveThread extends Thread{
private Socket socket;
public ReceiveThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
while(true){
try {
System.out.println(br.readLine());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端:
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Client {
@SuppressWarnings("all")
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1",8080);
Scanner scan = new Scanner(System.in);
new ReceiveThread(socket).start();
//发送给服务端信息
while(true ){
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("客户端:"+scan.next());
}
}
}
服务端:
import java.io.IOException;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class Server {
@SuppressWarnings("all")
public static void main(String[] args) throws IOException, InterruptedException {
//创建服务端的ServerSocket
ServerSocket server = new ServerSocket(8080);
Scanner scan = new Scanner(System.in);
Socket socket = server.accept();
new ReceiveThread(socket).start();
while(true){
//发送给客户端信息
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("服务端:"+scan.next());
}
}
}
示例2:客户端连接服务端,从服务端下载文件
注:示例下载视频文件(.mp4)采用带缓冲区的字节流传输。
服务端:
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
@SuppressWarnings("all")
public static void main(String[] args) throws IOException, InterruptedException {
//创建服务端的ServerSocket
ServerSocket server = new ServerSocket(8080);
Socket socket = server.accept();
OutputStream os = socket.getOutputStream();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("111.mp4"));
byte [] bs =new byte[1024];
int len;
while((len=bis.read(bs))!=-1){
os.write(bs, 0, len);
}
os.close();
bis.close();
}
}
客户端:
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.io.InputStream;
public class Client {
@SuppressWarnings("all")
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1",8080);
InputStream is = socket.getInputStream();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("download.mp4"));
byte [] bs =new byte[1024];
int len;
while((len=is.read(bs))!=-1){
bos.write(bs, 0, len);
}
is.close();
bos.close();
}
}
19.7.2 拓展示例
19.7.3 TCP的交互(三次握手和四次挥手)
三次握手成功,建立联系,开始传输数据
四次挥手成功,数据传输结束,双方断开
19.8 UDP编程
19.8.1 简介
UDP(User Datagram Protocol)用户数据报包协议,UDP和TCP位于同一层-传输层,但它对于数据包的顺序错误或重发没有TCP可靠;UDP是一种面向无连接的通信协议。UDP向应用程序提供一种发送封装的原始IP数据包的方法,并且发送时无需建立连接,不保证可靠数据的传输 。
19.8.2 使用示例
示例1:简单通信
客户端1
public class Client_1 {
public static void main(String[] args) throws IOException {
/**
* udp协议
*/
DatagramSocket socket = new DatagramSocket();
byte [] bs="Hello~~哈喽".getBytes();
//创建发送数据的数据包。
//包中有:发送的数据、数据的长度、接受数据的主机ip地址、端口号
DatagramPacket packet = new DatagramPacket(bs, bs.length, InetAddress.getByName("127.0.0.1"), 8080);
//使用socket发送数据包
socket.send(packet);
//创建存放接收数据的容器
byte [] buf=new byte[1024];
//设置接收数据的数据包
packet = new DatagramPacket(buf, buf.length);
//使用socket接收数据
socket.receive(packet);
System.out.println(new String(buf).trim());
//关闭资源
socket.close();
}
}
客户端2
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Client_2 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(8080);
//接收数据的容器
byte [] bs =new byte[1024];
//设置数据包
DatagramPacket packet = new DatagramPacket(bs, bs.length);
//使用套接字接收数据包
socket.receive(packet);
System.out.println(new String(bs).trim());
//发送数据
byte [] buf ="你好!".getBytes();
packet = new DatagramPacket(buf, buf.length,packet.getSocketAddress());
socket.send(packet);
//关闭资源
socket.close();
}
}
注:
- UDP协议中收发数据使用 receive/send方法。
- 数据包收发数据都是使用字符数组。
- UDP允许数据收发时遗失。
示例2:使用UDP协议进行一对一聊天(多线程)
用来接收数据的线程:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveThread extends Thread{
private DatagramSocket socket;
public ReceiveThread(DatagramSocket socket) {
this.socket = socket;
}
@Override
public void run() {
byte [] buf=new byte[1024];
System.out.println(new String(buf).trim());
while (true){
try {
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
System.out.println(new String(buf).trim());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
用来发送数据的线程:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class SendThread extends Thread{
private DatagramSocket socket;
private String ip;
private String name;
private int port;
public SendThread(DatagramSocket socket, String ip, String name, int port) {
this.socket = socket;
this.ip = ip;
this.name = name;
this.port = port;
}
@SuppressWarnings("all")
@Override
public void run() {
Scanner scan =new Scanner(System.in);
byte[] bs =null;
while (true){
bs=(name+":"+scan.next()).getBytes();
try {
DatagramPacket packet = new DatagramPacket(bs, bs.length,InetAddress.getByName(ip), port);
socket.send(packet);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端1:
public class Client_1 {
public static void main(String[] args) throws IOException {
/**
* udp协议
*/
DatagramSocket socket = new DatagramSocket(7070);
//开启发送数据的线程
new SendThread(socket, "127.0.0.1", "小明", 8080).start();
//开启接收数据的线程
new ReceiveThread(socket).start();
}
}
客户端2:
public class Client_2 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(8080);
//开启发送数据的线程
new SendThread(socket, "127.0.0.1", "小红", 7070).start();
//开启接收数据的线程
new ReceiveThread(socket).start();
}
}
19.9 TCP和UDP的比较
比较表:
TCP | UDP | |
---|---|---|
是否连接 | 面向连接 | 无面向连接 |
传输可靠性 | 可靠 | 不可靠 |
应用场合 | 传输大量数据 | 少量数据 |
速度 | 慢 | 快 |
19.20 HttpURLConnection(了解Resquest及Response)
简单示例介绍:(下载网络图片)
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
public class Test_2 {
public static void main(String[] args) throws IOException {
//网络接口
String urlStr = "https://p0.ssl.qhimgs1.com/sdr/400__/t018b0c452a789b9b2a.jpg" ;
//创建网络连接对象
URL url = new URL(urlStr);
//获取HttpURLConnection对象
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置
conn.setRequestMethod("GET");//请求方式
conn.setConnectTimeout(5000);//连接超时时间
conn.setReadTimeout(5000);//读取超时时间
//获取响应状态码
int responseCode = conn.getResponseCode();
if(responseCode==200){
BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("cop.jpg"));
byte [] cs =new byte[1024];
int len;
while((len=bis.read(cs))!=-1){
bos.write(cs, 0, len);
}
bos.close();
}else if(responseCode==404){
System.out.println("访问对象不存在");
}
}
}
;//请求方式
conn.setConnectTimeout(5000);//连接超时时间
conn.setReadTimeout(5000);//读取超时时间
//获取响应状态码
int responseCode = conn.getResponseCode();
if(responseCode==200){
BufferedInputStream bis = new BufferedInputStream(conn.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("cop.jpg"));
byte [] cs =new byte[1024];
int len;
while((len=bis.read(cs))!=-1){
bos.write(cs, 0, len);
}
bos.close();
}else if(responseCode==404){
System.out.println("访问对象不存在");
}
}
}