网络编程概述
网络的发展,缩小了人与人之间的时空距离。比如:小李在广东,小张在美国,现在通过即时通信软件就可以聊天,就像生活在隔壁一样。交流从未如此便捷!
信件:
计算机网络:
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
网络编程的目的:
数据交换,实现数据通信。
想要达到这个效果需要什么?
- 如何准确定义到网络上的一台主机?
通过IP地址+端口号,可以确定一台主机,如 168.192.1.1:端口
端口是用来区分计算机的不同程序。 - 找到了这个主机,如何传输数据?
javaweb:网页编程 B/S
网络编程:TCP/IP C/S
网络通信的要素
人工智能:智能汽车用在工厂,人少的地方
如何实现网络的通信?
- 需要通信双方的地址:
- ip
- 端口号
如:192.168.1.5:8000
- 规则:网络通信的协议
TCP/IP参考模型:
我们学习Java重点研究传输层:
小结:
- 网络编程中有两个主要的问题
- 如何准确的定位到网络上的一台主机
- 找到主机之后如何进行通信
- 网络编程中的要素
- IP 和 端口号
- 网络通信协议
- 在Java中,万物皆对象,使用对象实现网络通信功能
IP
java.net.InetAddress类
InetAddress类是用来表示互联网协议IP地址。
ip地址:
- 唯一定位一台网络上计算机
- 127.0.0.1 是本机的局域网地址,也可以用localhost替代
- ip地址的分类
- ipv4 / ipv6
- ipv4:由4个字节组成,共32位,0~255,一共有42亿个IPv4地址。如:192.168.1.6
- ipv6:由8个无符号整数组成,共128位。如:fe80::2999:2945:31c:838d%7
- 公网(互联网)- 私网(局域网)
- ABCD类地址
- 像192.168.xxx.xxx 是局域网,专门给组织内部使用。
- 域名:是为了解决IP地址难记忆的方法
package com.net.demo01;
import java.net.InetAddress;
import java.net.UnknownHostException;
/*
测试ip地址
使用InetAddress类的常用方法
*/
public class Demo01 {
public static void main(String[] args) {
try {
//查询本机地址
//创建InetAddress对象
InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1");
System.out.println(inetAddress1);
InetAddress inetAddress3 = InetAddress.getByName("localhost");
System.out.println(inetAddress3);
InetAddress inetAddress4 = InetAddress.getLocalHost();
System.out.println(inetAddress4);
//查询网站ip地址
InetAddress inetAddress2 = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress2);
//其他常用方法
System.out.println(inetAddress2.getAddress());
System.out.println(inetAddress2.getCanonicalHostName()); //规范的名字
System.out.println(inetAddress2.getHostAddress()); //ip
System.out.println(inetAddress2.getHostName()); //域名,或者自己电脑的名字
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
端口
端口表示计算机上的一个程序的进程:
- 不同的进程有不同的端口号!用来区分软件。
- 端口号的范围:0~65535
- TCP和UDP总端口数:65535*2,相同端口号在不同协议下不冲突,如:TCP:80,UDP:80,这是可以的。
- 端口分类
- 公共端口 0~1023
- HTTP:80
- HTTPS:443
- FTP:21
- SSH:22
- Telnet:23
- 程序注册端口:1024~49151,分配给用户或程序
- Tomcat:8080
- MySQL:3306
- Oracle:1521
- 动态、私有:49152~65535
CMD命令: netstat -ano //查看所有端口 netstat -ano|findstr "9240" //查看指定的端口 tasklist|findstr "9240" //查看指定端口的进程 //使用任务管理器查看
package com.net.demo01; import java.net.InetSocketAddress; /* 使用端口地址 */ public class Demo02 { public static void main(String[] args) { InetSocketAddress socketAddress1 = new InetSocketAddress("127.0.0.1", 8080); InetSocketAddress socketAddress2 = new InetSocketAddress("localhost", 8080); System.out.println(socketAddress1); System.out.println(socketAddress2); System.out.println(socketAddress1.getAddress()); //地址 System.out.println(socketAddress1.getHostName()); //域名 System.out.println(socketAddress1.getPort()); //端口 } }
通信协议
协议:就是约定,比如现在我们日常交流都是用普通话。
网络通信协议:速率、传输码率、代码结构、传输控制......
网络通信协议非常复杂,我们把它们进行分层:
TCP/IP协议簇,由一堆协议组成
- TCP:传输控制协议
- UDP:用户数据报协议
- IP:网际协议
TCP 和 UDP 对比
TCP:打电话
- 连接,稳定
- 三次握手,四次挥手
//最少需要三次,才能保证稳定连接! A:你愁啥? B:瞅你咋地? A:干一场! //四次挥手 A:我要走了! B:你真的要走了吗? B:你真的真的要走了吗? A:我真的走了!
- 客户端、服务端
- 传输完成后释放连接,效率低
UDP:发短信
- 不连接,不稳定
- 客户端、服务端没有明确界限
- 不管有没有准备好,都可以发给你...
- 导弹攻击
- DDoS:洪水攻击!饱和式打击
TCP
客户端
- 连接服务器 Socket
- 发送信息
package com.net.demo02;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
/*
客户端
*/
public class TcpClientDemo01 {
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
//1.要知道服务器的地址,端口号
try {
InetAddress serverIP = InetAddress.getByName("127.0.0.1");
int port = 9999;
//2.创建一个socket连接
socket = new Socket(serverIP, port);
//3.发送信息io流
os = socket.getOutputStream();
os.write("蚌埠住了".getBytes());
//刷新管道
os.flush();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
服务端
- 建立服务的端口 ServerSocket
- 等待用户的连接 accept
- 接收用户的信息
package com.net.demo02;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
服务端
*/
public class TcpServerDemo01 {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
ByteArrayOutputStream bos = null;
try {
//1.创建一个Socket,指定端口号
serverSocket = new ServerSocket(9999);
while (true) {
//2.等待客户端连接过来
socket = serverSocket.accept();
//3.读取客户端的消息
is = socket.getInputStream();
//管道流
bos = new ByteArrayOutputStream();
byte[] bytes = new byte[1024];
int readCount = 0;
while ((readCount = is.read(bytes)) != -1) {
bos.write(bytes, 0 ,readCount);
}
System.out.println(bos.toString());
//刷新管道
bos.flush();
}
// byte[] buffer = new byte[1024];
// int len;
// while ((len = is.read(buffer)) != -1) {
// bos.write(buffer, 0 ,len);
// }
// System.out.println(buffer.toString());
} catch (IOException e) {
e.printStackTrace();
}finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
文件上传
服务器端:
package com.net.demo02;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServerDemo02 {
public static void main(String[] args) {
ServerSocket serverSocket = null;
Socket socket = null;
InputStream is = null;
FileOutputStream fos = null;
try {
//1.创建服务器端口
serverSocket = new ServerSocket(9000);
//2.监听客户端的连接
socket = serverSocket.accept(); //阻塞式监听,会一直等待客户端连接
//3.获取输入流
is = socket.getInputStream();
//4.文件输出
fos = new FileOutputStream(new File("基础语法\\src\\com\\net\\demo02\\receive.jpg"));
byte[] bytes = new byte[1024];
int readCount = 0;
while ((readCount = is.read(bytes)) != -1) {
fos.write(bytes, 0, readCount);
}
//通知客户端我接收完毕了
OutputStream os = socket.getOutputStream();
os.write("服务器接收完毕,你可以断开了".getBytes());
//刷新管道
fos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (serverSocket != null) {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
客户端:
package com.net.demo02;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class TcpClientDemo02 {
public static void main(String[] args) {
Socket socket = null;
OutputStream os = null;
FileInputStream fis = null;
try {
//1.创建一个Socket连接
socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000);
//2.创建一个输出流
os = socket.getOutputStream();
//3.读取文件
fis = new FileInputStream(new File("基础语法\\src\\com\\net\\ia_3800000581.jpg"));
//4.写出文件
byte[] bytes = new byte[1024];
int readCount = 0;
while ((readCount = fis.read(bytes)) != -1) {
os.write(bytes, 0, readCount);
}
//通知服务器,我已经结束了
socket.shutdownOutput(); //我已经传输完了!
//确定服务器接收完毕,才能断开连接
InputStream is = socket.getInputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] bytes2 = new byte[1024];
int readCount2 = 0;
while ((readCount2 = is.read(bytes2)) != -1) {
baos.write(bytes2, 0, readCount2);
}
System.out.println(baos.toString());
//刷新管道
os.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Tomcat
客户端
- 自定义 C
- 浏览器 B
服务器
- 自定义 S
- Tomcat服务器 S Java后台开发!
UDP
发短信:不用连接,但需要知道对方的地址。
java.net.DatagramPacket类
发送消息
发送端:
package com.net.demo03;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
//不需要连接服务器
public class UdpClientDemo01 {
public static void main(String[] args) throws Exception {
//1.创建一个Socket
DatagramSocket socket = new DatagramSocket();
//2.建个包
String msg = "你好,服务器!";
//发送给谁
InetAddress localhost = InetAddress.getByName("localhost");
int port = 9090;
//数据,数据的长度起始,要发送给谁
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);
//3.发送包
socket.send(packet);
//4.关闭流
socket.close();
}
}
接收端:
package com.net.demo03;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//还是要等待客户端的连接
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();
}
}
循环发送消息
发送端:
package com.net.demo04;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
/*
发送端
*/
public class UdpSenderDemo01 {
public static void main(String[] args) throws Exception {
//创建Socket
DatagramSocket socket = new DatagramSocket(8888);
//准备数据:从控制台读取 System.in
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String data = reader.readLine();
byte[] datas = data.getBytes();
DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, new InetSocketAddress("localhost", 6666));
//发送信息
socket.send(packet);
if (data.equals("bye")) {
break;
}
}
reader.close();
socket.close();
}
}
接收端:
package com.net.demo04;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/*
接收端
*/
public class UdpReceiveDemo01 {
public static void main(String[] args) throws Exception {
//创建Socket
DatagramSocket socket = new DatagramSocket(6666);
while (true) {
//接收数据包
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);
socket.receive(packet); //阻塞式接收数据包
//断开连接
byte[] data = packet.getData();
String receiveData = new String(data, 0, data.length);
System.out.println(receiveData);
if (receiveData.equals("bye")) {
break;
}
}
socket.close();
}
}
多线程发送信息
线程类要实现Runnable接口
开启发送端线程:
package com.net.demo04;
public class TalkStudent {
public static void main(String[] args) {
//开启两个线程
new Thread(new TalkSend(7777, "localhost", 9999)).start();
new Thread(new TalkReceive(8888, "老师")).start();
}
}
开启接收端线程:
package com.net.demo04;
public class TalkTeacher {
public static void main(String[] args) {
//开启两个线程
new Thread(new TalkSend(5555, "localhost", 8888)).start();
new Thread(new TalkReceive(9999, "学生")).start();
}
}
发送端线程:
package com.net.demo04;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
/*
发送端线程
*/
public class TalkSend implements Runnable {
DatagramSocket socket = null;
BufferedReader reader = null;
private int formPort;
private String toIP;
private int toPort;
public TalkSend(int formPort, String toIP, int toPort) {
this.formPort = formPort;
this.toIP = toIP;
this.toPort = toPort;
try {
//创建Socket
socket = new DatagramSocket(formPort);
//准备数据:从控制台读取 System.in
reader = new BufferedReader(new InputStreamReader(System.in));
} catch (SocketException e) {
e.printStackTrace();
}
}
public void run() {
while (true) {
String data = null;
try {
data = reader.readLine();
byte[] datas = data.getBytes();
DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, new InetSocketAddress(this.toIP, this.toPort));
//发送信息
socket.send(packet);
if (data.equals("bye")) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
接收端线程:
package com.net.demo04;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/*
接收端线程
*/
public class TalkReceive implements Runnable {
DatagramSocket socket = null;
private int port;
private String msgForm;
public TalkReceive(int port, String msgForm) {
this.port = port;
this.msgForm = msgForm;
//创建Socket
try {
socket = new DatagramSocket(port);
} catch (SocketException e) {
e.printStackTrace();
}
}
public void run() {
while (true) {
try {
//接收数据包
byte[] bytes = new byte[1024];
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length);
socket.receive(packet); //阻塞式接收数据包
//断开连接
byte[] data = packet.getData();
String receiveData = new String(data, 0, data.length);
System.out.println(msgForm + ":" + receiveData);
if (receiveData.equals("bye")) {
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
URL
URL就是统一资源定位符,用来定位资源位置,可以准确找到互联网上的一个资源。
DNS域名解析服务:把域名解析为IP地址。
如:www.baidu.com -> 14.215.177.38
URL格式:
协议://ip地址:端口号/项目名/资源
从网站下载资源
通过URL在网站下载文件:
前提是需要获得资源的URL地址
- 使用Chrome的检查功能获取URL
package com.net.demo05;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/*
使用URL从网站下载资源
http://localhost:8080/siming/ia_3800000574.jpg
*/
public class URLDownload {
public static void main(String[] args) throws Exception {
//1.创建URL对象,放入下载地址
// URL url = new URL("http://localhost:8080/siming/ia_3800000574.jpg");
URL url = new URL("https://dl.stream.qqmusic.qq.com/C400001zLvbN1NYMuv.m4a?guid=1841897314&vkey=76015862ECD29189DDD7E35E449CEF1EB146E49924A0BE0AF859111C561CC9FB934EDF63EB3B199EE5CB3286BC737536312A82CC59E65CDA&uin=1040330915&fromtag=66");
//2.连接到这个资源,使用HTTP协议
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
//3.下载
InputStream is = urlConnection.getInputStream();
// FileOutputStream fos = new FileOutputStream("ia_3800000574.jpg");
FileOutputStream fos = new FileOutputStream("C:\\Users\\Siming\\Downloads\\Music\\桥边姑娘.m4a");
//一边读,一边写
byte[] bytes = new byte[1024];
int readCount = 0;
while ((readCount = is.read(bytes)) != -1) {
fos.write(bytes, 0, readCount);
}
//刷新管道
fos.flush();
//关闭
fos.close();
is.close();
urlConnection.disconnect(); //断开URL连接
}
}