一、初识网络编程
网络编程的概念:在网络通信协议下,不同计算机上运行的程序,进行的数据传输。
应用场景:即时通信、网游对战、金融证券、国际贸易、邮件等等。
不管是什么场景,都是计算机和计算机之间通过网络进行数据传输。
Java中可以使用java.net包下的技术开发出常见的网络应用程序。
二、常见的软件架构
(一)B/S架构
概念:只需要一个浏览器,用户通过不同的网址,可以访问不同的服务器。例如京东和淘宝。
优缺点:
- 不需要开发客户端,只需要开发服务端
- 用户不需要下载,打开浏览器就能使用
- 如果应用过大,用户体验受到影响
(二)C/S架构
概念:在用户本地需要下载并安装客户端程序,在远程有一个服务端程序。例如QQ、Steam。
优缺点:
- 画面可以做的非常精美,用户体验好
- 需要开发客户端,也需要开发服务端
- 用户需要下载和更新的时候太麻烦
有些软件,例如京东和淘宝,既又C/S架构,也有B/S架构。
三、网络编程三要素
(一)IP
IP:(Internet Protocol)是互联网协议地址,也称IP地址,是设备在网络中的地址,是唯一的标识。常见的IP分为:IPv4、IPv6
1.IPv4
IPv4:(Internet Protocol version4)是互联网通信协议第四版。 采用32为地址长度,分成4组,每组取值范围是0~255,一共有42亿多,为了方便记忆,最后采用点分十进制表示法,例如:192.168.1.66。但是ipv4已经分配完毕了,所以需要ipv6进行补充。
IPv4的地址分类形式:
- 公网地址(万维网使用)和私有地址(局域网使用)。
- 192.168.开头的就是私有地址,范围是192.168.0.0--192.168.255.255,专门为组织机构内部使用,以此节省IP。
特殊IP地址:127.0.0.1,也可以是localhost:是回送地址,也称本地回环地址,又称本机IP,永远只会寻找当前所在本机。
检查网络常用的CMD命令:
- ipconfig:查看本机IP地址
- ping:检查网络是否连通
2.IPv6
IPv6:(Internet Protocol version6)是互联网通信协议第六版。采用128位地址长度,分成8组。IPv6一共有2^128次方个IP,采用冒分十六进制表示法:
目前也有很多APP支持IPv6。
3.InetAddress的使用
public class MyInetAddressDemo1 {
public static void main(String[] args) throws UnknownHostException {
/*
static InetAddress getByName(String host) 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址
String getHostName() 获取此IP地址的主机名
String getHostAddress() 返回文本显示中的IP地址字符串
*/
// 1.获取InetAddress的对象
// IP的对象 一台电脑的对象
InetAddress address = InetAddress.getByName("PC-20240723RWZC");
System.out.println(address); // PC-20240723RWZC/192.168.0.4
String hostName = address.getHostName();
System.out.println(hostName); // PC-20240723RWZC
String hostAddress = address.getHostAddress();
System.out.println(hostAddress); // 192.168.0.4
}
}
(二)端口号
端口号:是应用程序在设备中唯一的标识。一个端口号只能被一个应用程序使用。
由两个字节表示的整数,取值范围:0~65535。其中0~1023的端口号用于一些知名的网络服务或者应用,我们使用1024以上的端口号即可。
以下是一些常见服务使用的端口号列表:这些端口号被IANA(Internet Assigned Numbers Authority)分配给特定的服务,并且广为人知。它们在网络通信中扮演着重要的角色,确保数据能够准确地发送到正确的服务。
- 21端口:FTP 文件传输服务。
- 22端口:SSH 远程连接服务。
- 23端口:TELNET 终端仿真服务。
- 25端口:SMTP 简单邮件传输服务。
- 53端口:DNS 域名解析服务。
- 80端口:HTTP 超文本传输服务。
- 110端口:POP3(E-mail)。
- 123端口:NTP(网络时间协议)。
- 135、137、138、139端口:局域网相关默认端口。
- 161端口:SNMP(简单网络管理协议)。
- 389端口:LDAP(轻量级目录访问协议)。
- 443端口:HTTPS服务器。
- 465端口:SMTP(简单邮件传输协议)。
- 873端口:rsync。
- 989端口:FTPS。
- 993端口:IMAPS。
- 995端口:POP3S。
- 1080端口:SOCKS代理协议服务器常用端口号。
- 1433端口:MS SQL*SERVER数据库server。
- 1521端口:Oracle 数据库。
- 3306端口:MYSQL数据库端口。
- 3389端口:WIN2003远程登录。
- 5432端口:postgresql数据库端口。
- 6379端口:Redis数据库端口。
- 8080端口:TCP服务端默认端口、JBOSS、TOMCAT。
(三)协议
1.协议概述
协议:是指数据在网络中传输的规则,常见的协议有UDP、TCP、http、https、ftp。
2.UDP协议
2.1UDP协议介绍
UDP协议又叫用户数据报协议(User Datagram Protocol),是面向无连接通信协议,不管是否已经连接成功,都会直接发送数据。
特点是:速度块,有大小限制,一次最多发送64K,数据不安全,易丢失数据。
UDP协议适用场景:网络会议、语音通话、在线视频,丢失数据没有太大的影响。
2.2使用UDP协议发送数据
步骤:
- 创建发送端的DatagramSocket对象
- 数据打包(DatagramPacket)
- 发送数据
- 释放资源
代码实现UDP协议发送数据:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class SendMessageDemo {
public static void main(String[] args) throws IOException {
// UDP协议发送数据
// 1.创建DatagramSocket对象
// 细节:绑定端口,以后就是通过这个端口往外发送
// 空参:所有可用的端口中随机一个进行使用
// 有参:指定端口号进行绑定
DatagramSocket datagramSocket = new DatagramSocket();
// 2.打包数据
String str = "hello world";
byte[] bytes = str.getBytes();
InetAddress address = InetAddress.getByName("127.0.0.1");
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, address, 10086);
// 3.发送数据
datagramSocket.send(datagramPacket);
// 4.释放资源
datagramSocket.close();
}
}
2.3使用UDP协议接收数据
步骤:
创建接收端的DatagramSocket对象
接收打包好的数据
解析数据包
释放资源
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketAddress;
public class ReceiveMessageDemo {
public static void main(String[] args) throws IOException {
// UDP协议接收数据
// 1.创建DatagramSocket对象
// 细节:在接收的时候,一定要绑定端口,而且绑定的端口一定要跟发送的端口保持一致
DatagramSocket datagramSocket = new DatagramSocket(10086);
// 2.接收数据包
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
// 该方法是阻塞的,程序执行到这一步的时候,会在这里等待发送端发送消息
datagramSocket.receive(datagramPacket);
// 3.解析数据包
byte[] data = datagramPacket.getData();
InetAddress address = datagramPacket.getAddress();
int length = datagramPacket.getLength();
int port = datagramPacket.getPort();
SocketAddress socketAddress = datagramPacket.getSocketAddress();
int offset = datagramPacket.getOffset();
System.out.println("接收到的数据:" + new String(data, 0, length));
System.out.println("该数据是从:" + address + "这台电脑中的" + port + "端口发出的");
System.out.println(socketAddress);
System.out.println("数据偏移量:" + offset);
// 4.释放资源
datagramSocket.close();
}
}
实现过程:
先启动接收程序,再启动发送程序,运行结果:
2.4使用UDP协议实现聊天室
案例需求
UDP发送数据:数据来自于键盘录入,直到输入的数据是886,发送数据结束
UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收
public class SendMessageDemo {
public static void main(String[] args) throws IOException {
// 1.创建对象DatagramSocket的对象
DatagramSocket datagramSocket = new DatagramSocket();
// 2.打包数据
Scanner scanner = new Scanner(System.in);
InetAddress address = InetAddress.getByName("127.0.0.1");
while (true) {
System.out.println("请输入消息:");
String str = scanner.nextLine();
if ("886".equals(str)) {
System.out.println("程序终止!");
break;
}
byte[] bytes = str.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, address, 10086);
// 3.发送数据
datagramSocket.send(datagramPacket);
}
// 4.释放资源
datagramSocket.close();
}
}
public class ReceiveMessageDemo {
public static void main(String[] args) throws IOException {
// 1.创建对象DatagramSocket的对象
DatagramSocket datagramSocket = new DatagramSocket(10086);
// 2.接收数据包
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
while (true) {
datagramSocket.receive(datagramPacket);
// 3.解析数据包
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
String ip = datagramPacket.getAddress().getHostAddress();
String hostName = datagramPacket.getAddress().getHostName();
int port = datagramPacket.getPort();
// 4.打印数据
System.out.println(hostName + "电脑的" + ip + ":" + port + "发送消息:" + new String(data, 0, length));
}
}
}
运行结果:
这里的hostName是activate.netsarang.com的原因是:在某些情况下,如果系统或网络环境中的 hosts 文件(在Windows中位于C:\Windows\System32\drivers\etc\hosts,在Unix/Linux系统中通常位于/etc/hosts)中有相应的条目,那么系统会直接从 hosts 文件中获取主机名,而不是去查询DNS。
我本地的host文件:找到第一个主机名返回
还可以设置多窗口聊天:
2.5UDP的三种通信方式
2.5.1单播——一对一通信(One-to-One)
在这种模式下,一个UDP套接字(客户端)向另一个UDP套接字(服务器)发送数据。客户端知道服务器的IP地址和端口号,可以直接向服务器发送数据包。服务器监听指定的端口,接收来自客户端的数据包。这种模式是最简单的UDP通信方式,适用于客户端和服务器之间的直接通信。
2.5.2组播——一对多通信(One-to-Many)
在一对多通信中,一个服务器向多个客户端发送数据。服务器使用相同的数据包发送给所有已知客户端的IP地址和端口号。这种模式常用于广播服务,如网络广播、在线游戏或多媒体流服务。服务器不需要为每个客户端维护一个单独的连接,而是向所有客户端广播数据。
组播地址:224.0.0.0~239.255.255.255
其中224.0.0.0~224.0.0.255为预留的组播地址
组播发送端代码:
public class SendMessageDemo {
public static void main(String[] args) throws IOException {
//创建MulticastSocket对象
MulticastSocket ms = new MulticastSocket();
// 创建DatagramPacket对象
String s = "hello world !";
byte[] bytes = s.getBytes();
InetAddress address = InetAddress.getByName("224.0.0.1");
int port = 10000;
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, address, port);
// 调用MulticastSocket发送数据方法发送数据
ms.send(datagramPacket);
// 释放资源
ms.close();
}
}
组播接收端代码:
public class ReceiveMessageDemo1 {
public static void main(String[] args) throws IOException {
// 1. 创建MulticastSocket对象
MulticastSocket ms = new MulticastSocket(10000);
// 2. 将当前本机,添加到224.0.0.1的这一组当中
InetAddress address = InetAddress.getByName("224.0.0.1");
ms.joinGroup(address);
// 3. 创建DatagramPacket数据包对象
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
// 4. 接收数据
ms.receive(dp);
// 5. 解析数据
byte[] data = dp.getData();
int len = dp.getLength();
String ip = dp.getAddress().getHostAddress();
String name = dp.getAddress().getHostName();
System.out.println("ip为:" + ip + ",主机名为:" + name + "的人,发送了数据:" + new String(data, 0, len));
// ip为:192.168.0.4,主机名为:PC-20240723RWZC的人,发送了数据:hello world !
// 6. 释放资源
ms.close();
}
}
接收端可以创建多个,但要保证每一个接收端都要将当前本机,添加到224.0.0.1的这一组当中。这样,发送端发送数据,多个接收端就可以同时接收到了。
2.5.3广播——多对多通信(Many-to-Many)
在多对多通信中,多个客户端之间可以直接相互通信,而不需要通过一个中心服务器。每个客户端都可以发送和接收来自其他客户端的数据包。这种模式适用于需要点对点通信的应用,如即时消息、文件共享或P2P网络。在这种模式下,每个客户端都扮演着发送者和接收者的角色。
广播地址:255.255.255.255
// 发送端
public class ClientDemo {
public static void main(String[] args) throws IOException {
// 1. 创建发送端Socket对象(DatagramSocket)
DatagramSocket ds = new DatagramSocket();
// 2. 创建存储数据的箱子,将广播地址封装进去
String s = "广播 hello";
byte[] bytes = s.getBytes();
InetAddress address = InetAddress.getByName("255.255.255.255");
int port = 10000;
DatagramPacket dp = new DatagramPacket(bytes,bytes.length,address,port);
// 3. 发送数据
ds.send(dp);
// 4. 释放资源
ds.close();
}
}
// 接收端
public class ServerDemo {
public static void main(String[] args) throws IOException {
// 1. 创建接收端的Socket对象(DatagramSocket)
DatagramSocket ds = new DatagramSocket(10000);
// 2. 创建一个数据包,用于接收数据
DatagramPacket dp = new DatagramPacket(new byte[1024],1024);
// 3. 调用DatagramSocket对象的方法接收数据
ds.receive(dp);
// 4. 解析数据包,并把数据在控制台显示
byte[] data = dp.getData();
int length = dp.getLength();
System.out.println(new String(data,0,length));
// 5. 关闭接收端
ds.close();
}
}
3.TCP协议
3.1TCP协议介绍
TCP协议:又叫传输控制协议(Transmission Control Protocol),是面向连接的通信协议。是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,通过Socket产生IO流来进行网络通信,通信之前要保证连接已经建立。
特点是:速度慢,没有大小限制,数据安全。
TCP协议适用场景:对于数据有非常高的要求,不能丢失任何数据,例如下载软件、文字聊天、发送邮件。
3.2使用TCP协议发送和接收数据
public class Client {
public static void main(String[] args) throws IOException {
// TCP协议,发送数据
// 1.创建Socket对象
// 细节:在创建对象的同时会连接服务端;如果连接不上,代码会报错
Socket socket = new Socket("127.0.0.1", 10001);
// 2.可以从连接通道中获取输出流
OutputStream os = socket.getOutputStream();
// 写出数据
os.write("hello world".getBytes());
// 3.释放资源
os.close();
socket.close();
}
}
public class Server {
public static void main(String[] args) throws IOException {
// TCP协议,接收数据
// 1.创建对象ServerSocket
ServerSocket serverSocket = new ServerSocket(10001);
// 2.监听客户端的连接
Socket socket = serverSocket.accept();
// 3.从连接通道中获取输入流读取数据
InputStream is = socket.getInputStream();
int len;
while ((len = is.read()) != -1) {
System.out.print((char) len);
}
// 4.释放资源
is.close();
socket.close();
}
}
先运行Server服务器,再运行Client客户端,运行结果:
3.3解决TCP传输过程中的中文乱码问题
上面的代码使用的是字节流传输,在传输中文时会产生乱码,我们可以使用BufferReader来接收:
public class Server2 {
public static void main(String[] args) throws IOException {
// TCP协议,接收数据
// 1.创建对象ServerSocket
ServerSocket serverSocket = new ServerSocket(10001);
// 2.监听客户端的连接
Socket socket = serverSocket.accept();
// 3.从连接通道中获取输入流读取数据
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
int len;
while ((len = br.read()) != -1) {
System.out.print((char) len);
}
// 4.释放资源
is.close();
socket.close();
}
}
运行结果: