网络编程
1.1 简介
网络缩短了时间和空间距离。
计算机网络:
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
网络编程的目的:
传播交流信息,数据交换,通信
想要打到这个效果需要什么:
- 定位网络上的主机:端口(192.168.16.124)
- 定位到计算机上的某个资源:APP
网络编程是利用TCP/IP,使用C/S架构;而javaweb是指网页编程,使用B/S架构,两者是不一样的。
1.2 网络通信的要素
需要的要素:
- ip+端口号:可以定位到某一台计算机上的具体的应用(192.168.16.124:5900)
- 网络通信协议:http,ftp,smtp,tcp,udp…
- TCP/IP参考模型:
补充:
通过域名查询IP
1.3 IP
ip地址:InetAddress
-
唯一定位一台网络上的计算机
-
127.0.0.1:本机/localhost
-
ip地址的分类
- IPV4/IPV6
- IPV4:127.0.0.1,4B
- IPV6: 2001:250:5833:2198:fd61:d3ff:3267:56ec,8B,09,ae
- 公网(互联网)和私网(局域网)
- 局域网:192.168.xx.xx,专门给组织内部使用的
- ABCDE类地址
- IPV4/IPV6
-
域名:为了记忆IP
- 互联网刚开始发展的时候,卖IP比房地产更挣钱
范例:
package lesson01;
import java.net.InetAddress;
import java.net.UnknownHostException;
//测试IP
public class TestInetAddress {
public static void main(String[] args) {
//没有构造器,不能new出来,只能通过静态方法返回
try {
//查询本机地址
InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1");
System.out.println(inetAddress1);
InetAddress inetAddress3 = InetAddress.getByName("localhost");
System.out.println(inetAddress1);
InetAddress inetAddress4 = InetAddress.getLocalHost();
System.out.println(inetAddress1);
//查询网络ip地址
InetAddress inetAddress2 = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddress2);
//常用方法 了解
System.out.println(inetAddress2.getAddress()); //该行代码通过inetAddress2.getAddress().sout+Enter 就可以快速生成
System.out.println(inetAddress2.getCanonicalHostName()); //获得规范的名字
System.out.println(inetAddress2.getHostAddress()); //获得域名或者本机的名字
System.out.println(inetAddress2.getHostName());
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
}
结果:
/127.0.0.1
/127.0.0.1
/127.0.0.1
www.baidu.com/39.156.66.14
[B@7f31245a
39.156.66.14
39.156.66.14
www.baidu.com
1.4 端口
如上图所示,PID表示port id,也就是端口id,端口表示计算机上一个程序的进程。
-
单个协议好端口号唯一,用来区分软件
-
端口号被规定为0~65535
-
TCP,UDP可以拥有相同的PID,因为是两种协议
-
端口分类
- 公有端口:0~1023 尽量不要用
- HTTP:80
- HTTPS:43
- FTP:21
- Telent:23
- 程序注册端口:1024~49151,分配给用户或者程序的
- Tomcat:8080
- MySQL:3306
- Oracle:1521
- 动态、私有端口:49152~65535 例如打开IDEA的文档会自动生成一个网页 尽量不要用
netstat -ano #查看所有的端口 netstat -ano|findstr "9636" #查看指定的端口 tasklist|findstr "17636" #查看指定端口的进程 Ctrl+shift+Esc #打开任务管理器
package lesson01; import java.net.InetSocketAddress; public class TestInetSocketAddress { public static void main(String[] args) { InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", 8080); //Alt+Enter 快速生成等号前面的部分 System.out.println(inetSocketAddress); InetSocketAddress inetSocketAddress2 = new InetSocketAddress("localhost", 8080); System.out.println(inetSocketAddress2); System.out.println(inetSocketAddress.getAddress()); //和前面相同 System.out.println(inetSocketAddress.getHostName()); //获得主机名字 就是/127.0.0.1:8080中的127.0.0.1 拓展:配置host文件 System.out.println(inetSocketAddress.getPort()); //获得端口号码 } } 结果: /127.0.0.1:8080 localhost/127.0.0.1:8080 /127.0.0.1 127.0.0.1 8080
- 公有端口:0~1023 尽量不要用
拓展:配置host
按照这样的配置打开host文件
可以在上图中配置本机的映射地址,这样getHostName()就会输出本机地址之外的地址
1.5 通信协议
关键词:速率,传输码率,代码结构,传输控制
TCP/IP协议簇(一组协议):
- TCP:用户传输协议
- UDP:用户数据报协议
- IP:网络互连协议
TCP和UDP的对比:
-
TCP:打电话
-
连接,稳定
-
三次握手,四次分手
-
# 最少需要三次,保证稳定连接 A:你愁啥? B:瞅你咋地? C:干一场! # 四次保证连接断开 A:我要走了 B;你真的要走了吗? B:你真的真的要走了吗? A:嗯
-
-
客户端和服务端
-
传输完成,释放连接,效率低
-
-
UDP:发短信
- 不连接,不稳定
- 客户端,服务端(因为是发包,没有明确谁是客户端谁是服务端)
- 不管准没准备好,都可以发给你
- DDOS:洪水攻击
1.6 TCP
客户端:
-
-
连接服务器 Socket
-
发送消息
-
package lesson2; 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()); } catch (Exception e) { e.printStackTrace(); }finally { if(socket!=null){ try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if(os!=null){ try { os.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
-
服务端:
-
-
建立服务的端口 ServerSocket
-
等待用户的连接 accept
-
接受用户的消息
-
package lesson2; 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 baos = null; //1. 要有一个服务器地址 try { //Java网络编程也称为套接字编程,因为需要接入 serverSocket = new ServerSocket(9999); while (true) { //用while循环持续对客户端进行监听,这样就会获得多个输出 //2. 等待客户端连接过来 socket = serverSocket.accept(); //3. 读取客户端的消息 is = socket.getInputStream(); //在服务器端和客户端之间增加一个管道流,以此来解决乱码等问题 baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { baos.write(buffer, 0, len); } //现在的输出还是字节数组,要toString一下 System.out.println(baos.toString()); } } catch (IOException e) { e.printStackTrace(); }finally { //关闭资源 //在大的项目中为了避免出现问题,需要添加if()判断 if(baos!=null){ try { baos.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) { } } if(serverSocket!=null){ try { serverSocket.close(); } catch (IOException e) { } } } } }
-
结果如下图所示:
1.7 文件上传
先运行服务器端
package lesson2;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class TcpServerDemo02 {
public static void main(String[] args) throws Exception {
//1. 创建服务端口
ServerSocket serverSocket = new ServerSocket(9000);
//2. 监听客户端的连接
Socket socket = serverSocket.accept();//阻塞式监听,会一直等待客户端连接 直到链接之后才会进行下面的代码
//原理如下两行代码所示:
// Scanner scanner = new Scanner(System.in);
//scanner.next();
//3. 获取输入流/拿到当前文件了
InputStream is = socket.getInputStream();
//4. 文件输出 拿到文件之后要加一个管道输出流,否则无法输出
FileOutputStream fos = new FileOutputStream(new File("receive.png"));
//创建好输出管道后,从有当前文件的is里面读
byte[] buffer = new byte[1024*2];
int len;
while ((len=is.read(buffer))!=-1){
fos.write(buffer,0,len);
}
//通知客户端接收完毕了
OutputStream outputStream = socket.getOutputStream();
outputStream.write("我接收完毕了,你可以断开了".getBytes());
//关闭资源
fos.close();
is.close();
socket.close();
serverSocket.close();
}
}
然后运行客户端
package lesson2;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class TcpclientDemo02 {
public static void main(String[] args) throws IOException {
//1. 创建一个socket连接
Socket socket = new Socket(InetAddress.getByName("10.22.66.155"), 9000);
//2. 创建一个输出流
OutputStream os = socket.getOutputStream();
//把文件变成流再输出出去
//3. 读取文件
FileInputStream fis = new FileInputStream(new File("狂神网络编程.png"));
//4. 写出文件
byte[] buffer2 = new byte[1024];
int len;
while ((len= fis.read(buffer2))!=-1){
os.write(buffer2,0,len);
}
//为了防止形成客户端自己写给自己的闭环,需要通知服务器自己已经传输完了
socket.shutdownOutput();
//确定服务器接收完毕,才能断开连接
InputStream inputStream = socket.getInputStream();
//String byte[]
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] bytes3 = new byte[2014];
int len2;
while ((len2 = inputStream.read(bytes3))!=-1){
byteArrayOutputStream.write(bytes3,0,len2);
}
System.out.println(byteArrayOutputStream.toString());
//5. 关闭资源、先写后关 尽量不要排除异常,否则就要写很多代码
byteArrayOutputStream.close();
inputStream.close();
fis.close();
os.close();
socket.close();
}
}
就会在下图所示的位置生成一个"receive.png",(自己写一直显示Connection refused,无法解决)
ping自己的电脑:
1.8 Tomcat
在1.7中我们是自定义了服务端和客户端(CS),下面介绍使用浏览器作为客户端、使用Tomcat服务器的BS。
未来Java的后台开发是使用别人的服务器
.bat是windows下的执行文件
.sh是Linux下的执行文件
如下图所示,启动Tomcat执行文件,会生成一个8080的端口(红线圈起来的部分是网站的域名)也就是开启了一个服务
然后在网络上搜索,就可以看到Tomcat网站
而关闭了服务端,就搜索不到Tomcat网站了
可以通过修改该文件来改变服务器端内容
可以通过"协议/IP端口/项目名/文件名"来的到搜索的内容
如果先启动Tomcat,然后执行程序,会报错。因为同一个协议中端口号不能重复
1.9 UDP发送消息
不需要连接,需要知道对方的地址
先启动服务端:
package lesson03;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
//还是要等待客户端的连接
public class UdpSeverDemo01 {
public static void main(String[] args) throws Exception {
//开放端口 UDP没有Sever这个概念,也是用socket
DatagramSocket socket = new DatagramSocket(9090);
//接收数据 这里的packet可以理解成“装快递用的袋子”
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();
}
}
结果:
127.0.0.1
你好啊,服务器!
再启动客户端:
package lesson03;
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(); //Datagram:数据报
//如果赋予客户端一个端口号,就可以接收别人发来的包
//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();
}
}
1.10 用UDP实现聊天
发送端:
package chat;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
public class UdpSenderDemo01 {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(8888);
//准备数据:控制台读取 System.in
// 也用包装流包起来 → new BufferedReader
//然后从控制台读取数据,因为System.in返回一个InputStream,所以new InputStreamReader(System.in)
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true){
String data = reader.readLine(); //data是reader中每一行数据,抽象概念
byte[] datas = data.getBytes(); //datas是转化后得到的具体、可读数据
DatagramPacket packet = new DatagramPacket(datas,0,datas.length,new InetSocketAddress("localhost",6666));
socket.send(packet);
if (datas.equals("bye")) break; //本地退出
}
socket.close();
}
}
接收端:
package chat;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UdpReceiveDemo01 {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(6666);
while (true){ //为了实现对话,也就是持续接收,需要添加while循环
//准备接收包裹
byte[] container = new byte[1024];
DatagramPacket packet = new DatagramPacket(container,0,container.length);
socket.receive(packet);//阻塞式接收包裹
//读取并断开连接
byte[] data = packet.getData();
String receiveData = new String(data, 0, data.length);
System.out.println(receiveData);
if(receiveData.equals("byte")){
break; //远程退出
}
}
socket.close();
}
}
结果:
1.11 UDP多线程在线咨询
在线咨询:两个人都可以是发送方,也都可以是接收方
TalkSend:
package com.yuboyao.chat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
public class TalkSend implements Runnable{ //是线程就要继承Runnable接口
DatagramSocket socket = null;
BufferedReader reader = null;
private int fromPort;
private String toIP;
private int toPort;
public TalkSend(int fromPort, String toIP, int toPort) {
this.fromPort = fromPort;
this.toIP = toIP;
this.toPort = toPort;
try {
socket = new DatagramSocket(fromPort);
reader = new BufferedReader(new InputStreamReader(System.in));
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
try{
String 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 (Exception e) {
e.printStackTrace();
}
}
socket.close();
}
}
TalkReceive:
package com.yuboyao.chat;
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 msgFrom;
public TalkReceive( int port,String msgFrom) {
this.port = port;
this.msgFrom = msgFrom;
//对socket = new DatagramSocket();使用Ctrl+Alt+T,选择try/catch围绕
try {
socket = new DatagramSocket(port);
} catch (SocketException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (true){
try {
//准备接收包裹
byte[] container = new byte[1024];
DatagramPacket packet = new DatagramPacket(container, 0,container.length);
socket.receive(packet);
//断开连接
byte[] data = packet.getData();
String receiveData = new String(data,0,data.length);
System.out.println(msgFrom+":"+receiveData);
if(receiveData.equals("bye")){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
socket.close();
}
}
两个线程TalkStudent和TalkTeacher,两个人都可以是接收方也可以是发送方
package com.yuboyao.chat;
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.yuboyao.chat;
public class TalkTeacher {
public static void main(String[] args) {
new Thread(new TalkSend(5555,"localhost",8888)).start();
new Thread(new TalkReceive(9999,"学生")).start();
}
}
然后打开文件夹模式,在路径上cmd + 空格,然后回车
依据包名,进行后退,然后调用TalkStudent
用cmd的学生和IDEA的老师进行聊天就能完成通信,虽然有乱码,但是不影响。
1.12URL
这两个都是URL
URL/统一资源定位符:定位资源的,定位互联网上的某一个资源
URL由5部分组成:
协议://ip地址:端口/项目名/资源
URL类:
package com.yuboyao.chat;
import java.net.MalformedURLException;
import java.net.URL;
public class URLDemo01 {
public static void main(String[] args) throws MalformedURLException {
URL url = new URL("http://localhost:8080/helloworld/index.jsp?username=yuboyao&password=123");
System.out.println(url.getProtocol()); //得到协议名 url.getProtocol().sout
System.out.println(url.getHost()); //主机名/IP
System.out.println(url.getPort()); //端口
System.out.println(url.getPath());//文件
System.out.println(url.getFile()); //文件全路径
System.out.println(url.getQuery()); //参数
}
}
结果:
http
localhost
8080
/helloworld/index.jsp
/helloworld/index.jsp?username=yuboyao&password=123
username=yuboyao&password=123
使用URL下载网络文件:
package com.yuboyao.chat;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
public class URLDown {
public static void main(String[] args) throws IOException {
//1.准备下载文件的地址
URL url = new URL("https://www.lddgo.net/common/stopwatch");
//2.建立下载链接
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
FileOutputStream jishiqi = new FileOutputStream("jishiqi");
byte[] buffer = new byte[1024];
int len;
while ((len=inputStream.read(buffer))!=-1){
jishiqi.write(0);
}
jishiqi.close();
inputStream.close();
urlConnection.disconnect();
}
}