目录
[TCP UDP 对比](#TCP UDP 对比)
一、网络编程
概述
地球村:现代科技的迅速发展,缩小了地球上的时空距离。可以进行快速的数据分享
计算机网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协商下,实现资源共享和信息传递的计算机系统
网络编程的目的:进行数据交换、通信
想要达到这个效果需要什么:
- 如何准确的定位网络上的一台主机 192.168.16.124: 端口,定位到这个计算机上的某个资源
- 找到了这个主机,如何传输数据呢?
- JavaWeb: 网页编程 B/S(浏览器/服务器)
- 网络编程: TCP/ IP C/S(客户端/服务器)
网络通信的要素、如何实现网络的通信?
通信双方地址:ip:端口号(192.168.16.124:5900)
规则:网络通信的协议
小结:
1.网络编程中有两个主要的问题
- 如何准确的定位到网络上的一台或者多台主机
- 找到主机之后如何进行通信
2.网络编程的要素
- ip 和 端口号
- 网络通信写协议
IP介绍
ip地址:InetAddress,唯一定位一台网络上计算机
127.0.0.1:本机localhost
ip地址的分类
1.ipv4/ipv6
ipv4:127.0.0.1,四个字节组成, 0~255,全球有42亿个ipv4地址,现在已经不够用了
ipv6:128位,8个无符号整数
2.公网(互联网) 私网(局域网)
ABCD地址
192.168.xx.xx,专门给组织内部的使用
域名:是为了更好的记忆IP!
使用Java查看IP地址
java
package com.example.websocketstudy.ip;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
public class getIP {
public static void main(String[] args) throws Exception {
//获取本地主机地址
InetAddress localhost = InetAddress.getByName("127.0.0.1");
System.out.println(localhost);
//获取本地主机地址
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);
//常用方法
//获取ip地址的字节数组
System.out.println(Arrays.toString(inetAddress2.getAddress()));
//获取规范的主机名
System.out.println(inetAddress2.getCanonicalHostName());
//获取主机地址
System.out.println(inetAddress2.getHostAddress());
//获取主机名
System.out.println(inetAddress2.getHostName());
}
}
端口
端口表示计算机上的一个程序的进程,不同的进程有不同的端口号!用来区分软件!
端口范围被规定:0~65535
TCP,UDP 共有:65535*2个端口,TCP:80 UDP:80 单个协议下,接口不能冲突
端口分类
1.公有端口0~1023(由电脑程序自动调用,不建议在自己的程序中使用)
- HTTP:80
- HTTPS:443
- FTP:21
- Telent:23
2.程序注册断口:1024~49151,分配用户或者程序
- Tomcat :8080
- MySQL:3306
- Oracle:1521
3.动态、私有:49152~65535
DOS窗口查看端口命令
java
netstat -ano #查看所有的窗口
netstat -ano|findstr "5900" # 查看指定的窗口
tasklist|findstr "8696"#查看指定窗口进程
CTRL + SHIFT +ESC 打开任务管理器
通信协议
通信协议是指双方实体完成通信或服务所必须遵循的规则和约定。通过通信信道和设备互连起来的多个不同地理位置的数据通信系统,要使其能协同工作实现信息交换和资源共享,它们之间必须具有共同的语言。交流什么、怎样交流及何时交流,都必须遵循某种互相都能接受的规则。这个规则就是通信协议
就好比我们现在需要沟通要求我们都使用普通话。
网络通信协议:速率、传输码率,代码结构,传输控制...
TCP/IP协议簇:实际上是一组协议
重要:
- TCP:用户传输协议
- UDP:用户数据报协议
出名的协议:
- TCP
- IP:网络互联协议
TCP UDP 对比
TCP:打电话(需要双方都在线才能进行数据交互)
- 连接,稳定
- 客户端、服务端
- 传输完成、释放连接、效率低
UDP: 发短信(发送用户不需要确认接收用户在不在线)
- 不连接,不稳定
- 客户端、服务端、没有明确的界限
- 不管有没有准备好,都可以发给你...
- DDOS :洪水攻击(洪水攻击是一种通过向目标系统发送过量数据使其服务瘫痪的黑客攻击技术,属于分布式拒绝服务(DDoS)攻击范畴。其核心原理为利用网络协议漏洞或资源消耗机制,向目标服务器的带宽、连接池或计算资源发起高强度请求,导致合法用户无法正常访问服务 )
TCP
客户端
- 连接服务器Socket
- 发送消息
Java实现客户端
java
public class TCPClientUploadFile {
public static void main(String[] args) throws Exception {
// 创建一个Socket对象,指定本地主机和端口号
Socket socket = new Socket("127.0.0.1", 8888);
// 获取Socket的输出流
OutputStream os = socket.getOutputStream();
// 创建一个文件输入流,读取本地文件
FileInputStream fis = new FileInputStream("D:\\Softs\\JavaCode\\WebSocketStudy\\tuo.jpg");
// 创建一个字节数组,用于存储读取的文件内容
byte[] bytes = new byte[1024];
// 定义一个变量,用于存储读取的字节数
int len;
// 循环读取文件内容,直到读取完毕
while ((len = fis.read(bytes)) != -1) {
// 将读取的内容写入输出流
os.write(bytes, 0, len);
}
// 关闭输出流
socket.shutdownOutput();
// 获取Socket的输入流
InputStream is = socket.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes1 = new byte[1024];
int len1;
while ((len1 = is.read(bytes1)) != -1) {
bos.write(bytes1, 0, len1);
}
System.out.println(bos.toString());
bos.close();
is.close();
fis.close();
// 关闭输出流
os.close();
}
}
Java实现服务端
- 监理服务端口
- 等待用户的连接accept
- 接受用户的消息
java
public class TCPServer {
public static void main(String[] args) throws Exception {
// 创建一个ServerSocket对象,监听8888端口
ServerSocket socket = new ServerSocket(8888);
// 等待客户端连接
Socket accept = socket.accept();
System.out.println("客户端连接成功");
// 获取输入流
InputStream is = accept.getInputStream();
// 创建一个字节数组,用于存储读取的数据
byte[] bytes = new byte[1024];
// 定义一个变量,用于存储读取的字节数
int len;
// 创建一个FileOutputStream对象,用于将接收到的数据写入文件
FileOutputStream fos = new FileOutputStream("receive.jpg");
// 循环读取数据
System.out.println("文件下载开始");
while ((len = is.read(bytes)) != -1) {
// 将读取的数据写入文件
fos.write(bytes, 0, len);
}
System.out.println("文件接收成功");
// 获取输出流
OutputStream os = accept.getOutputStream();
// 向客户端发送上传成功的消息
os.write("接收文件成功你可以断开了".getBytes());
// 关闭输出流
os.close();
// 关闭文件输出流
fos.close();
// 关闭输入流
is.close();
// 关闭ServerSocket
socket.close();
}
}
代码实现整体流程:

Tomcat
服务端
- 自定义 Service
- Tomcat服务器Service: Java后台开发
客户端
- 自定义 Client
- 浏览器 Browser
UDP
发信件:不用连接,需要知道对方的地址!
使用Java实现两个用户循环发送消息
java
public class UDPUserOne {
public static void main(String[] args) throws Exception {
// 获取本地主机地址
InetAddress address = InetAddress.getByName("127.0.0.1");
// 设置fas端口号
int sendPort = 8888;
// 设置接收端口号
int receivePort = 9999;
// 创建DatagramSocket对象
DatagramSocket sendSocket;
// 创建DatagramPacket对象
DatagramPacket packet;
//
DatagramSocket receiveSocket = new DatagramSocket(receivePort);
// 创建Scanner对象
Scanner scanner;
byte[] bytes = new byte[1024];
// 创建DatagramPacket对象,用于接收数据
DatagramPacket receivePackage;
System.out.println("UserOne 已经准备接收数据");
// 无限循环
while (true) {
// 提示用户输入发送内容
System.out.print("请输入发送内容:");
// 创建Scanner对象
scanner = new Scanner(System.in);
// 获取用户输入的内容
String sendData = scanner.nextLine();
// 创建DatagramSocket对象
sendSocket = new DatagramSocket();
// 创建DatagramPacket对象,指定发送的数据、数据长度、目标地址和端口号
packet = new DatagramPacket(sendData.getBytes(), sendData.getBytes().length, address, sendPort);
// 发送数据
sendSocket.send(packet);
// 如果用户输入的内容为exit,则退出循环
if ("exit".equals(sendData)) {
System.out.println("关闭对话");
break;
}
// 输出内容已发送
System.out.println("内容已发送,等待回复...");
// 创建DatagramPacket对象,用于接收数据
receivePackage = new DatagramPacket(bytes, bytes.length);
// 接收数据
receiveSocket.receive(receivePackage);
// 将接收到的数据转换为字符串
String receiveData = new String(receivePackage.getData(), 0, receivePackage.getLength());
System.out.println("接收文件内容:" + receiveData);
// 如果用户输入的内容为exit,则退出循环
if ("exit".equals(receiveData)) {
System.out.println("关闭对话");
break;
}
}
// 关闭DatagramSocket对象
sendSocket.close();
receiveSocket.close();
}
}
java
public class UDPUserTwo {
public static void main(String[] args) throws Exception {
// 定义端口号
int receivePort = 8888;
// 定义发送端口号
int sendPort = 9999;
// 创建UDP套接字
DatagramSocket receiveSocket = new DatagramSocket(receivePort);
// 创建数据报包
DatagramPacket receivePackage;
// 创建字节数组
byte[] bytes = new byte[1024];
// 创建扫描器
Scanner scanner;
// 定义地址
InetAddress address = InetAddress.getByName("127.0.0.1");
// 创建数据报包
DatagramPacket sendPackage;
//
DatagramSocket sendSocket = new DatagramSocket();
System.out.println("UserTwo 已经准备接收数据");
// 无限循环
while (true) {
// 创建数据报包
receivePackage = new DatagramPacket(bytes, 0, bytes.length);
// 接收数据报包
receiveSocket.receive(receivePackage);
// 将字节数组转换为字符串
String receiveData = new String(receivePackage.getData(), 0, receivePackage.getLength());
// 输出接收到的数据
System.out.println("接收文件内容:" + receiveData);
// 如果接收到的数据为exit,则退出循环
if ("exit".equals(receiveData)) {
System.out.println("关闭对话");
break;
}
System.out.print("请输入发送内容:");
// 如果接收到的数据不为exit,则发送数据
scanner = new Scanner(System.in);
// 获取用户输入
String sendData = scanner.nextLine();
// 创建数据报包
sendPackage = new DatagramPacket(sendData.getBytes(), sendData.getBytes().length, address, sendPort);
// 发送数据
sendSocket.send(sendPackage);
System.out.println("内容已发送,等待回复...");
}
// 关闭套接字
receiveSocket.close();
sendSocket.close();
}
核心内容:
发送方:需要使用Socket发送已经写好的信件,信件中需要只要写明收件方的详细地址(IP、Port)
java
// 创建DatagramPacket对象,指定发送的数据、数据长度、目标地址和端口号
packet = new DatagramPacket(sendData.getBytes(), sendData.getBytes().length, address, sendPort);
// 发送数据
sendSocket.send(packet);
接收方:需要查看邮箱(Port)是否收到信息,将收到的信件进行保存、查看
java
// 关注邮箱
new DatagramSocket(receivePort);
// 创建数据报包
receivePackage = new DatagramPacket(bytes, 0, bytes.length);
// 接收数据报包
receiveSocket.receive(receivePackage);
// 将字节数组转换为字符串
String receiveData = new String(receivePackage.getData(), 0, receivePackage.getLength());
使用多线程方式实现循环接收、发送数据
接收数据
java
package com.example.websocketstudy.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class ReceiveDataThread implements Runnable {
// 定义接收数据的线程
private final String fromName;
// 定义接收数据的字节数组
private static final byte[] bytes = new byte[1024];
// 定义接收数据的DatagramSocket
DatagramSocket receiveSocket;
// 构造函数,传入接收数据的线程名和接收数据的端口号
public ReceiveDataThread(String fromName, int receivePort) throws SocketException {
this.fromName = fromName;
// 设置当前线程的名称
Thread.currentThread().setName(fromName);
// 创建接收数据的DatagramSocket
receiveSocket = new DatagramSocket(receivePort);
}
// 实现Runnable接口的run方法
@Override
public void run() {
try {
// 无限循环,接收数据
while (true) {
// 打印接收数据的线程名
System.out.println(fromName + "正在接收数据...");
// 创建接收数据的DatagramPacket
DatagramPacket receivePacket = new DatagramPacket(bytes, bytes.length);
// 接收数据
receiveSocket.receive(receivePacket);
// 将接收到的字节数组转换为字符串
String receiveData = new String(receivePacket.getData(), 0, receivePacket.getLength());
// 打印接收到的数据内容
System.out.println("收到数据内容为:" + receiveData);
// 如果接收到的数据为exit,则退出循环
if ("exit".equals(receiveData)) {
break;
}
}
// 关闭接收数据的DatagramSocket
receiveSocket.close();
} catch (IOException e) {
// 抛出运行时异常
throw new RuntimeException(e);
}
}
}
发送数据
java
package com.example.websocketstudy.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;
public class SendDataThread implements Runnable {
// 定义发送端口号
private final int sendPort;
private final String fromName;
// 定义接收端IP地址
private final String toIP;
private final DatagramSocket sendSocket;
// 构造函数,初始化发送端口号和接收端IP地址
public SendDataThread(int sendPort, String fromName, String toIP) throws SocketException {
this.sendPort = sendPort;
this.toIP = toIP;
this.fromName = fromName;
Thread.currentThread().setName(fromName);
sendSocket = new DatagramSocket();
}
// 实现Runnable接口的run方法
@Override
public void run() {
// 创建发送端的DatagramSocket
try {
while (true) {
// 根据接收端IP地址获取InetAddress对象
InetAddress sendAddress = InetAddress.getByName(toIP);
// 打印当前线程的名称
System.out.println(fromName + "请输入发送内容:");
// 从控制台读取发送内容
String sendData = new Scanner(System.in).nextLine();
// 将发送内容转换为字节数组
DatagramPacket sendPacket = new DatagramPacket(sendData.getBytes(), sendData.getBytes().length, sendAddress, sendPort);
// 发送数据包
sendSocket.send(sendPacket);
if ("exit".equals(sendData)) {
break;
}
// 打印发送成功信息
System.out.println("数据已发送,等待接收数据...");
}
// 关闭发送端的DatagramSocket
sendSocket.close();
} catch (IOException e) {
// 抛出运行时异常
throw new RuntimeException(e);
}
}
}
实例化
java
public class QiYuThread {
public static void main(String[] args) throws SocketException {
new Thread(new SendDataThread(8888, "埼玉", "localhost")).start();
new Thread(new ReceiveDataThread("埼玉", 1111)).start();
}
}
java
public class FlashThread {
public static void main(String[] args) throws SocketException {
new Thread(new SendDataThread(1111, "闪光", "localhost")).start();
new Thread(new ReceiveDataThread("闪光", 8888)).start();
}
}