Java网络编程
目录
一、网络编程
概述
网络通信的要素、如何实现网络的通信?
小结:
IP介绍
ip地址的分类
端口
端口分类
通信协议
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地址
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窗口查看端口命令
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实现客户端
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
- 接受用户的消息
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();// 关闭ServerSocketsocket.close();}
}
代码实现整体流程:
Tomcat
服务端
- 自定义 Service
- Tomcat服务器Service: Java后台开发
客户端
- 自定义 Client
- 浏览器 Browser
UDP
发信件:不用连接,需要知道对方的地址!
使用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();}
}
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)
// 创建DatagramPacket对象,指定发送的数据、数据长度、目标地址和端口号
packet = new DatagramPacket(sendData.getBytes(), sendData.getBytes().length, address, sendPort);
// 发送数据
sendSocket.send(packet);
接收方:需要查看邮箱(Port)是否收到信息,将收到的信件进行保存、查看
// 关注邮箱
new DatagramSocket(receivePort);
// 创建数据报包
receivePackage = new DatagramPacket(bytes, 0, bytes.length);
// 接收数据报包
receiveSocket.receive(receivePackage);
// 将字节数组转换为字符串
String receiveData = new String(receivePackage.getData(), 0, receivePackage.getLength());
使用多线程方式实现循环接收、发送数据
接收数据
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];// 定义接收数据的DatagramSocketDatagramSocket receiveSocket;// 构造函数,传入接收数据的线程名和接收数据的端口号public ReceiveDataThread(String fromName, int receivePort) throws SocketException {this.fromName = fromName;// 设置当前线程的名称Thread.currentThread().setName(fromName);// 创建接收数据的DatagramSocketreceiveSocket = new DatagramSocket(receivePort);}// 实现Runnable接口的run方法@Overridepublic void run() {try {// 无限循环,接收数据while (true) {// 打印接收数据的线程名System.out.println(fromName + "正在接收数据...");// 创建接收数据的DatagramPacketDatagramPacket 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;}}// 关闭接收数据的DatagramSocketreceiveSocket.close();} catch (IOException e) {// 抛出运行时异常throw new RuntimeException(e);}}
}
发送数据
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方法@Overridepublic void run() {// 创建发送端的DatagramSockettry {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("数据已发送,等待接收数据...");}// 关闭发送端的DatagramSocketsendSocket.close();} catch (IOException e) {// 抛出运行时异常throw new RuntimeException(e);}}
}
public class QiYuThread {public static void main(String[] args) throws SocketException {new Thread(new SendDataThread(8888, "埼玉", "localhost")).start();new Thread(new ReceiveDataThread("埼玉", 1111)).start();}
}
public class FlashThread {public static void main(String[] args) throws SocketException {new Thread(new SendDataThread(1111, "闪光", "localhost")).start();new Thread(new ReceiveDataThread("闪光", 8888)).start();}
}
至此鸣谢:狂神说Java学习笔记——网络编程_狂神说 网络编程-CSDN博客