网络编程
概述

计算机网络:
- 计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统、网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。
网络编程的目的:
- 传播交流信息、数据交换、通信
想要达到这个效果需要什么:
- 如何准确的定位网络上的一台主机:IP地址+端口,定位到这个计算机上的某个资源(进程)
- 找到了这台主机,如何传输数据?
JavaWeb:网页编程 B/S架构
网络编程:TCP/IP C/S架构
网络通信的要素
如何实现网络的通信:
-
通信双方的地址
- IP(唯一的)
- 端口号
-
规则:
网络通信的协议
-
TCP/IP 参考模型
小结:
- 网络编程中有两个主要的问题
- 如何准确的定位到网络上一台或者多台主机
- 找到主机后如何进行通信
- 网络编程中的要素
- IP和端口号
- 网络通信协议
- 万物皆对象
IP

IP地址:Inetdress
- 唯一定位一台网络上的计算机
- 127.0.0.1:本机localhost
- IP地址的分类
- ipv4/ipv6
- IPV4:127.0.0.1,四个字节组成,0-255,大概42亿个;30亿都在北美,亚洲4亿,2011年已经用尽。
- IPV6:128位,8个无符号16进制的数,两个连续的冒号是省略了0。a-f,a表示10,f表示15(0-15;16进制)
- 公网-私网
- 公网:互联网使用,也就是上面的42亿
- ABCD类地址
- 私网:局域网
- ipv4/ipv6
- 域名:记忆IP问题
package ip;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 测试IP
*/
public class TestInetAddress {
public static void main(String[] args) {
try {
// 查询本机地址
InetAddress inetAddresses1 = InetAddress.getByName("127.0.0.1");
System.out.println(inetAddresses1);
InetAddress inetAddresses2 = InetAddress.getByName("localhost");
System.out.println(inetAddresses2);
InetAddress inetAddresses3 = InetAddress.getLocalHost();
System.out.println(inetAddresses3);
// 查询网站ip地址
InetAddress inetAddresses4 = InetAddress.getByName("www.baidu.com");
System.out.println(inetAddresses4);
// 常用方法
// 返回一个字节数组地址
System.out.println(inetAddresses4.getAddress());
// 获得规范的IP
System.out.println(inetAddresses4.getCanonicalHostName());
// 获得IP
System.out.println(inetAddresses4.getHostAddress());
// 获得域名或者自己电脑的名字
System.out.println(inetAddresses4.getHostName());
} catch (UnknownHostException e) {
throw new RuntimeException(e);
}
}
}
运行结果:

端口
表示计算机上的一个程序的进程
-
不同的进程有不同的端口号,端口号不能冲突,用来区分软件。
-
端口被规定为0~65535
-
TCP/IP 各有65535个端口,TCP用了80,UDP也可以用80,单个(同一) 协议下,端口号不能冲突。
-
端口分类:
-
共有端口:0-1023
- HTTP:80
- HTTPS:443
- FTP:21
- Telent:23
-
程序注册端口:1024-49151,分配用户或者程序
- Tomcat:8080
- MySQL:3306
- Oracle:1521
-
动态、私有:491152-65535
# 常用来查看端口占用 # 使用任务管理器查看进程 netstat -ano #查看所有端口状态 netstat -ano|findstr "端口号" #查看具体端口状态 tasklist|findstr "进程ID" #查询该端口的进程是什么
Ctrl + Shift + ESC—> 打开任务管理器
-
package ip;
import java.net.InetSocketAddress;
public class TestSocketAddress {
public static void main(String[] args) {
InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8080);
InetSocketAddress socketAddress2 = new InetSocketAddress("localhost", 8080);
System.out.println(socketAddress);
System.out.println(socketAddress2);
System.out.println(socketAddress.getAddress());
// 地址
System.out.println(socketAddress.getHostName());
// 端口
System.out.println(socketAddress.getPort());
}
}
运行结果:

-
一个主机上的进程的端口号需要找到另一个主机上相同端口号的进程建立连接。
通信协议
协议:约定
网络通信协议:针对网络产生一种协议,速率、传输码率、代码结构、传输控制……
问题:非常的复杂
因此出现了分层!
TCP/IP协议簇实际上是一组协议,其中两个最具代表性的传输层协议,分别是TCP和UDP。
重要:
- TCP:用户传输协议
- UDP:用户数据报协议
- IP:网络互连协议
TCP和UDP对比:
- TCP:相当于打电话
- 连接稳定
- 三次握手,四次挥手
- 客户端、服务端
- 传输完成,释放连接,效率低,但稳定
- UDP:相当于发短信
- 无连接,不稳定
- 客户端、服务端:没有明确的界限
- 不管有没有准备好,都可以发送
- DDos:泛洪攻击,端口堵塞
TCP
客户端和服务端
客户端:
-
连接服务器,通过 Socket
-
发送消息
package TCP; import java.io.IOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; /** * 客户端 */ 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("你好,欢迎学习狂神Java".getBytes()); } catch (Exception e) { throw new RuntimeException(e); } finally { if (os != null) { try { os.close(); } catch (IOException e) { throw new RuntimeException(e); } } if (socket != null) { try { socket.close(); } catch (IOException e) { throw new RuntimeException(e); } } } } }
服务器:
-
建立服务的端口 ServerSocket
-
等待用户的连接 accept
-
接收用户的消息
package TCP; import java.io.ByteArrayInputStream; 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 { serverSocket = new ServerSocket(9999); // 2.等待客户端连接过来 socket = serverSocket.accept(); // 3.读取客户端的消息 is = socket.getInputStream(); /* 此方法容易出现乱码问题 byte[] bytes = new byte[1024]; int len; while ((len = is.read(bytes)) != -1) { String msg = new String(bytes, 0, len); System.out.println(msg); } */ // 管道流 baos = new ByteArrayOutputStream(); byte[] bytes = new byte[1024]; int len; while ((len = is.read(bytes)) != -1) { baos.write(bytes, 0, len); } System.out.println(baos); } catch (IOException e) { throw new RuntimeException(e); } finally { // 关闭资源:先开的最后关 if (baos != null) { try { baos.close(); } catch (IOException e) { throw new RuntimeException(e); } } if (baos != null) { try { is.close(); } catch (IOException e) { throw new RuntimeException(e); } } if (baos != null) { try { socket.close(); } catch (IOException e) { throw new RuntimeException(e); } } if (baos != null) { try { serverSocket.close(); } catch (IOException e) { throw new RuntimeException(e); } } } } }
运行结果:

TCP实现文件上传
-
服务器:
package TCP; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; public class TcpServerDemo02 { public static void main(String[] args) throws Exception { // 1.创建服务 ServerSocket serverSocket = new ServerSocket(9000); // 2.监听客户端的连接诶 /*serverSocket.accept(); 阻塞式监听。会一直等待客户端连接*/ Socket socket = serverSocket.accept(); // 3.获取输入流 InputStream is = socket.getInputStream(); // 4.文件输出 FileOutputStream fos = new FileOutputStream(new File("receive.png")); byte[] bytes = new byte[1024]; int len; while((len = is.read(bytes)) != -1) { fos.write(bytes, 0, len); } // 通知客户端接收完毕了 OutputStream os = socket.getOutputStream(); os.write("我接收完毕了,你可以断开了".getBytes()); // 5.关闭资源 fos.close(); is.close(); socket.close(); } }
-
客户端:
package TCP; import java.io.*; import java.net.InetAddress; import java.net.Socket; public class TcpClientDemo02 { public static void main(String[] args) throws Exception { // 1.创建一个Socket连接 Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9000); // 2.创建一个输出流 OutputStream os = socket.getOutputStream(); // 3.读取文件 FileInputStream fis = new FileInputStream(new File("test.png")); // 4.写出文件 byte[] bytes = new byte[1024]; int len; while ((len = fis.read(bytes)) != -1) { os.write(bytes, 0, len); } // 通知服务器,我已经传输结束了 socket.shutdownOutput(); // 确定服务器接收完毕,才能够断开连接 InputStream inputStream = socket.getInputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] bytes1 = new byte[1024]; int len2; while((len2 = inputStream.read(bytes1)) != -1) { baos.write(bytes1, 0, len2); } System.out.println(baos); // 5.关闭资源 baos.close(); inputStream.close(); fis.close(); os.close(); socket.close(); } }

初识Tomcat
服务端
- 自定义
- Tomcat服务器:Java后台开发
客户端
- 自定义
- 浏览器
下图为Tomcat文件夹

-
开启
bin目录下startup.bat
-
关闭
bin目录下shutdown.bat
-
检查
开启之后,在浏览器输入:
localhost:8080
查看是否访问成功 -
使用方法
localhost:8080\(webapps目录下的项目文件夹名\(项目文件夹中的文件名)
-
启动时候的乱码问题
打开conf目录下logging.ptoperties文件,将

第47行中的UTF-8改为GBK,可以解决打开Tomcat出现乱码问题。
如果我们使用(占用)着8080端口,启动Tomcat就会报错。
UDP
相当于发短信:不用连接,但需要知道对方的地址。

UDP没有服务器和客户端的概念,这里只是用来演示举例。
UDP发送消息
-
发送端
package UDP; 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 = "你好啊!服务器"; // 3.发送给谁 InetAddress localhost = InetAddress.getByName("localhost"); int port = 9090; // 参数:数据,数据的长度,起始,要发送给谁, DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port); // 4.发送包 socket.send(packet); // 5.关闭流 socket.close(); } }
-
接收端
package UDP; 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(); } }
UDP实现聊天
循环发送消息
发送端
package UDP.chat;
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 {
DatagramSocket socket = new DatagramSocket(8888);
// 准备数据:控制台读取 System.in
BufferedReader reader = new BufferedReader(new InputStreamReader((System.in)));
while(true) {
String data = reader.readLine();
byte[] bytes = data.getBytes();
DatagramPacket packet = new DatagramPacket(bytes, 0, bytes.length, new InetSocketAddress("localhost", 6666));
socket.send(packet);
if (data.equals("bye")){
break;
}
}
socket.close();
}
}
接收端
package UDP.chat;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UdpReceiveDemo01 {
public static void main(String[] args) throws Exception {
DatagramSocket socket = new DatagramSocket(6666);
byte[] container = new byte[1024];
while (true) {
// 准备接收包裹
DatagramPacket packet = new DatagramPacket(container, 0, container.length);
// 阻塞式接收包裹
socket.receive(packet);
// 断开连接 bye
byte[] data = packet.getData();
String receiveData = new String(data, 0, data.length);
System.out.println(receiveData);
if (receiveData.equals("bye")) {
break;
}
}
socket.close();
}
}
实现两个人都能进行发送和接收(多线程)
发送端
package UDP.chat;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
public class TalkSend implements Runnable {
DatagramSocket socket = null;
BufferedReader reader = null;
private String toIP;
private int fromPort;
private int toPort;
public TalkSend(int fromPort, String toIP, int toPort) {
this.toIP = toIP;
this.fromPort = fromPort;
this.toPort = toPort;
try {
socket = new DatagramSocket(fromPort);
reader = new BufferedReader(new InputStreamReader(System.in));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
try {
while (true) {
String data = reader.readLine();
byte[] datas = data.getBytes();
DatagramPacket packet = new DatagramPacket(datas, 0, datas.length, new InetSocketAddress(toIP, toPort));
socket.send(packet);
if (data.equals("bye")) {
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
socket.close();
}
}
接收端
package UDP.chat;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
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;
try {
socket = new DatagramSocket(port);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void run() {
byte[] container = new byte[1024];
while (true){
try {
//准备接收包裹
DatagramPacket packet = new DatagramPacket(container,0,container.length);
//阻塞式接收包裹
socket.receive(packet);
//断开连接
byte[] data = packet.getData();
String receiveData = new String(data, 0, packet.getLength());
System.out.println(msgFrom + ":" + receiveData);
//trim去掉字符串首尾的空格
if (receiveData.trim().equals("bye")){
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
socket.close();
}
}
学生
package UDP.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 UDP.chat;
public class TalkTeacher {
public static void main(String[] args) {
new Thread(new TalkSend(5555, "localhost", 8888)).start();
new Thread(new TalkReceive(9999, "学生")).start();
}
}
测试结果:


URL
统一资源定位符:定位资源的,定位互联网上的某一个资源。
DNS域名解析:将域名解析为IP
协议://ip地址:端口/项目名/资源
package URL;
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=kuangshen&password=123");
// 协议
System.out.println(url.getProtocol());
// 主机IP
System.out.println(url.getHost());
// 端口
System.out.println(url.getPort());
// 文件全路径
System.out.println(url.getPath());
// 文件
System.out.println(url.getFile());
// 参数
System.out.println(url.getQuery());
}
}
运行结果:

从网上下载资源
package URL;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class URLDown {
public static void main(String[] args) throws Exception {
// 1.下载地址
URL url = new URL("https://img2.wallspic.com/previews/2/7/1/4/7/174172/174172-luo_ke_xi_desr_71hei_niao-luo_ke_xi_de_ma_dingsr_72-luo_ke_xi_de_yf_12-pen_qi_shi_fei_ji-bei_mei_x_15-500x.jpg");
// 2.连接到这个资源 HTTP
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
InputStream inputStream = urlConnection.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream("pic.jpg");
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1){
// 写出这个数据
fileOutputStream.write(bytes, 0, len);
}
fileOutputStream.close();
inputStream.close();
urlConnection.disconnect();
}
}
下载结果:
随便找了一张图测试了一下

ok还挺有意思哈哈哈哈