# 网络编程
在通信协议下,不同计算机上运行的程序,进行的数据传输
# 常见软件架构
# CS架构(Client/Server)客户端/服务器
在用户本地需要下载并安装客户端程序,在远程有一个服务端程序
# BS架构(Browser/Server)浏览器/服务器
只需要一个浏览器,用户通过不同的网址。客户访问不同的服务器
# 网络编程三要素
- 确定双方ip地址
- 端口号 一个软件只有一个 应用程序的唯一标识 其中0~1023之间的端口号被用于一些一直的网络服务或者应用,自己使用1024以上的端口号
- 协议。数据在网络中的传输规则.常见协议有 UDP、TCP、HTTP、HTTPS
# 协议
# tcp/ip参考模型

# udp协议
- 用户数据报协议(User Datagram Protocol)
- UDP是面向无连接通信协议(不管是否已经连接成功) 速度快,有大小限制一次最多发送64K,数据不安全,易丢失数据
# tcp协议
- 传输控制协议TCP(Transmission Control Protocol)
- TCP协议是面向连接的通信协议,(使用tcp的三次握手,从而确定连接)
- 速度慢,没有大小限制,数据安全
# inetAddress类获取本机对象
package Network;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class main {
public static void main(String[] args) throws UnknownHostException {
//inetAddress类 获取本机ip对象
InetAddress byName = InetAddress.getByName("DESKTOP-ET3DHBQ");//使用当前主机名获取ip对象
System.out.println(byName);
System.out.println(byName.getHostName());//获取主机名称
System.out.println(byName.getHostAddress());//获取主机ip地址
//获取当前设备IP
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost.getHostAddress());
}
}
# 使用UDP协议发送和接收数据
DatagramSocket类发送和接收数据
# 发送数据
public class main {
public static void main(String[] args) throws IOException {
//发送数据
// 1.创建DatagramSocket对象
//细节:
//绑定端口号,以后我们就是通过这个端口往外发送数据
//空参:所有可用的端口中随机一个进行使用
//带参:指定端口号进行使用
//1.指定端口号进行绑定
DatagramSocket ds = new DatagramSocket();
//2.打包数据
byte[] bytes = "hello".getBytes();
//3.发送的数据目的地(DESKTOP-ET3DHBQ 这台电脑)
InetAddress address = InetAddress.getByName("DESKTOP-ET3DHBQ");
//参数 字节数组 数据长度 目的地 端口号
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, 10086);
//发送数据
ds.send(dp);
//释放资源
ds.close();
}
}
# 接收数据
public class main {
public static void main(String[] args) {
//创建DatagramSocket对象 指定端口接口
DatagramSocket ds = new DatagramSocket(10086);
//创建接收字节数组
byte[] bytes = new byte[1024];
//接收数据
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
//接收数据
//程序在执行这一步时,会在这里死等
//等待发送端发送消息
ds.receive(datagramPacket);
//释放资源
ds.close();
//解析数据包
byte[] data = datagramPacket.getData();
//获取数据包的长度
int length = datagramPacket.getLength();
System.out.println("发送的数据" + new String(data, 0, length));
System.out.println("发送端主机名称" + datagramPacket.getAddress().getHostAddress());
System.out.println("端口号" + datagramPacket.getPort());
}
}
# UDP聊天室
package Network;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class ChatRoom {
//UDP聊天室
public static <T> void main(String[] args) throws IOException {
//开启发送端
Thread thread = new Thread(new FutureTask<T>(new UDPServer<>()));
//先开启接收端
Thread thread1 = new Thread(new FutureTask<T>(new UDPClient<>()));
thread.start();
thread1.start();
}
}
//服务器1发送数据
class UDPServer<T> implements Callable<T> {
@Override
public T call() throws Exception {
//创建DatagramSocket对象 指定端口接口
//创建对象
DatagramSocket ds = new DatagramSocket();
//获取键盘输入对象
Scanner sc = new Scanner(System.in);
//接收键盘录入
int i = 0;
while (i != 886) {
System.out.println("请输入数字");
i = sc.nextInt();
//打包数据
byte[] bytes = String.valueOf(i).getBytes();
//3.发送的数据目的地(DESKTOP-ET3DHBQ 这台电脑)
InetAddress address = InetAddress.getByName("DESKTOP-ET3DHBQ");
//参数 字节数组 数据长度 目的地 端口号
DatagramPacket dp = new DatagramPacket(bytes, bytes.length, address, 10086);
//发送数据
ds.send(dp);
}
//释放资源
ds.close();
return null;
}
}
//客户端1接收数据
class UDPClient<T> implements Callable<T> {
public T call() throws Exception {
//创建DatagramSocket对象 指定端口接口
//创建对象
DatagramSocket ds = new DatagramSocket(10086);
//创建接收字节数组(新进来的数据会覆盖旧数据)
byte[] bytes = new byte[1024];
//定义接收格式
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
while (true) {
//接收数据
ds.receive(datagramPacket);
//数据处理
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
System.out.println("接收到的数据为" + new String(data, 0, length));
System.out.println("接收端主机名称" + datagramPacket.getAddress().getHostAddress());
System.out.println("端口号" + datagramPacket.getPort());
}
}
}
# TCP通信程序
TCP通信协议是一种可靠的网络协议.他在通信的两端各建立一个Socket对象,通信之前要保证链接已经建立
- 通过
Socket产生IO流来进行网络通信
package Network;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class Tcp {
public static void main(String[] args) {
//使用tcp协议发送数据
//创建多线程对象 同时运行服务端和客户端
Thread server = new Thread(new FutureTask<>(new SocketServer<>()));
Thread client = new Thread(new FutureTask<>(new SocketClient<>()));
//开启线程
client.start();
server.start();
}
}
//客户端发送数据
class SocketClient<T> implements Callable<T> {
@Override
public T call() throws IOException {
//使用tcp协议发送数据
//发送数据使用Socket对象
//1.创建Socket对象
//在创建对象时同时会链接服务器
//如果链接不上服务器 那么就会报错
//参数(链接的ip,端口)
Socket socket = new Socket("127.0.0.1", 10086);
//2.可以从链接通道中获取输出流写出数据
//注意:字节流只能写出字节数组
socket.getOutputStream().write("你好4566".getBytes());
return null;
}
}
//服务端接收数据
class SocketServer<T> implements Callable<T> {
@Override
public T call() throws IOException {
//使用tcp协议接收数据
//接收数据使用ServerSocket对象
//1.创建ServerSocket对象
//注意发送方和接收方的端口要一致
ServerSocket serversocket = new ServerSocket(10086);
//2.监听客户端的链接
//如果一直没有客户端来连 那么程序将会卡死在这行代码上
//如果有客户端来连,那么将会返回一个Socket对象
Socket socket = serversocket.accept();
// //2.可以从链接通道中获取输入流读取数据
// //注意:字节流只能读取字节数组
// byte[] bytes = new byte[1024];
InputStream is = socket.getInputStream();
//将字节流转换为字符流 以便设置读取的编码规则
InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8);
//使用字符缓冲流
BufferedReader br = new BufferedReader(isr);
int b;
while ((b = br.read()) != -1) {
System.out.print("客户端发送的数据" + (char) b);
}
//释放资源
socket.close();
//关闭服务器
serversocket.close();
return null;
}
}
# 文件上传
package Network;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
public class FileTcp {
//文件上传
public static void main(String[] args) throws Exception {
//创建多线程对象
SocketFileClient socketFileClient = new SocketFileClient();
SocketFileServer socketFileServer = new SocketFileServer();
Thread client = new Thread(new FutureTask<>(socketFileClient));
Thread server = new Thread(new FutureTask<>(socketFileServer));
//开启线程
client.start();
server.start();
}
}
//客户端发送文件
class SocketFileClient<T> implements Callable<T> {
@Override
public T call() throws Exception {
//读取本地文件中的数据
File file = new File("attrs\\file\\ZipStreamDemo\\网络爬虫-姓名爬取.txt");
//创建Tcp文件传输对象
Socket socket = new Socket("127.0.0.1", 10086);
//创建转换流对象
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file));
//获取输出流
BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream());
byte[] bytes = new byte[1024];
int len;
//循环读取文件
while ((len = bufferedInputStream.read(bytes)) != -1) {
//发送数据
//注意一定要用socket中的输出流来写出数据
//尽管包装成高级流,但包装完成的发送无响应
System.out.println("发送数据" + len);
outputStream.write(bytes, 0, len);
}
//释放资源
bufferedInputStream.close();
outputStream.close();
//注意:要把所有流关闭才能发送结束标记 、、否则会提前结束
//发送结束标记
socket.shutdownOutput();
socket.close();
return null;
}
}
//服务端接收文件
class SocketFileServer<T> implements Callable<T> {
@Override
public T call() throws Exception {
//获取接收对象
ServerSocket serversocket = new ServerSocket(10086);
//监听客户端连接
Socket socket = serversocket.accept();
//链接成功后可以从链接通道中获取数据
BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
byte[] bytes = new byte[1024];
int len;
//获取输出流对象写入本地文件
//使用uuid 生成不重复的文件名
File file = new File("attrs\\file\\ZipStreamDemo", "网络爬虫-姓名爬取-文件上传" + UUID.randomUUID().toString().replaceAll("-", "") + ".txt");
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(file));
while ((len = bufferedInputStream.read(bytes)) != -1) {
//将获取的数据写入本地文件
bufferedOutputStream.write(bytes, 0, len);
}
//传输完毕释放资源
bufferedInputStream.close();
bufferedOutputStream.close();
serversocket.close();
socket.close();
return null;
}
}
← 多线程