0
点赞
收藏
分享

微信扫一扫

Java编程基础之网络编程


网络编程

文章目录

  • ​​网络编程​​
  • ​​概述​​
  • ​​C/S和B/S​​
  • ​​网络通信协议​​
  • ​​网络编程要素​​
  • ​​IP类​​
  • ​​UDP协议数据传输​​
  • ​​发送端​​
  • ​​接收端​​
  • ​​udp数据传输丢失问题​​
  • ​​TCP概述​​
  • ​​Socket客户端​​
  • ​​ServerSocket服务端Socket​​
  • ​​**服务器代码**​​
  • ​​客户端代码​​
  • ​​文件上传实现​​
  • ​​客户端​​
  • ​​服务端​​
  • ​​多线程版​​

概述

C/S和B/S

Java编程基础之网络编程_java

网络通信协议

协议:protocol

网络通信协议市要求双方传递数据的计算机必须遵守的,按照对应的网络传输协议,才可以进入数据的交互和传递

常见协议:

  • UDP
    面向无连接,不可靠数据传输存在丢包
    传输速度快
    没有客户端和服务器区别,都可以作为发送端和接收端
    使用场景:直播,网络游戏
  • TCP/IP
    面向连接
    可靠数据传输,稳定
    有明确服务器和客户端概念
    使用场景:数据下载,文件传输

网络编程要素

  1. 协议
    两个计算机之间数据传输,需要对应的协议来完成
  2. IP地址
    Internet Protocol Address
    当前计算机在网络中的一个地址编号,类似于手机号码
    IP地址有IPv4和IPv6两种格式
  3. 端口号
    端口号是当前应用程序在计算机中的一个编号,是计算机明确,当前的数据是给予哪一个程序使用,或者数据从哪一个程序发出
    端口号是一个short类型数据,范围0-65535
    0-1024属于特定的系统端口号,不能自定义使用

IP类

InetAddress

常用方法:

  • InetAddress getLocalhost();
    获取本机IP地址类对象
  • InetAddress getByName(String str);
    根据指定的主机名获取对应的IP地址对象
  • InetAddress[] getAllByName(String str);
    获取指定主机名,或者域名对应的所有IP地址类对象

package cn.ocean888;

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Demo1 {
public static void main(String[] args) throws UnknownHostException {
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);


InetAddress byNameAddress = InetAddress.getByName("秦的机械革命");
System.out.println(byNameAddress);


InetAddress byNameAddress2 = InetAddress.getByName("www.ocean888.cn");
System.out.println(byNameAddress2);


InetAddress[] byNameAddress3 = InetAddress.getAllByName("www.baidu.com");
for (InetAddress inetAddress : byNameAddress3) {
System.out.println(inetAddress);
}
}
}

Java编程基础之网络编程_客户端_02

UDP协议数据传输

用户数据报协议:User Datagram Protocol

数据传递采用数据包方式传递,所有的数据要进行打包操作,并且没有对应的客户端服务器概念,有且只有发送端和接收端

Socket 套接字

数据在需要进行传递操作时,在数据传递的两台计算机当中必须有对应的Socket,这里采用UDP协议,则必须有一个UDP协议的Socket

DatagramSocket();
创建一个发送端UDP协议Socket对象

DatagramSocket(int port);
创建一个接收端UDP协议的Socket对象,这里需要监听指定端口

数据包的打包方法

发送端数据打包方式

DatagramPacket DatagramPacket(byte[] buf, int length, InetAddress address, int port);

/*
buf:需要传递数据的字节数组
length:当前字节数组中数据容量字节数
address:接收端IP地址对象
port:接收端对应的端口号
*/

接收端数据接收方式

需要准备一个空的数据包
DatagramPacket DatagramPacket(byte[] buf, int length);

/*
buf:字节缓冲数组,通常是1024的整数倍
length:当前字节缓冲数组的容量
*/

发送端

步骤:

  1. 创建UDP服务器对应的发送端Socket
  2. 准备对应的数据包,需要带有指定数据
  3. 发送数据 send
  4. 发送 udp 发送端

package cn.ocean888;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class SenderDemo1 {
public static void main(String[] args) throws IOException {
System.out.println("udp发送端");

// 创建对应的Socket
DatagramSocket socket = new DatagramSocket();

// 准备数据包
byte[] bytes = "ocean".getBytes();
DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 8848);

// 发送数据包
socket.send(packet);

// 关闭udp发送端
socket.close();
}
}

接收端

步骤:

  1. 打开UDP服务,监听指定端口
  2. 创建新的空数据包
  3. 通过Socket接受数据 receive
  4. 关闭 UDP 接收端

package cn.ocean888;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class ReceiveDemo1 {
public static void main(String[] args) throws IOException{
System.out.println("接收端启动");
// 创建socket监听端口
DatagramSocket socket = new DatagramSocket(8848);

// 准备空数据包
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);

// 接收数据
socket.receive(packet);

// 确定接受到的字节长度
int length = packet.getLength();

System.out.println(new String(buf, 0, length));

// 关闭socket
socket.close();
}
}

需要先启动接收端,监听端口

Java编程基础之网络编程_客户端_03

udp数据传输丢失问题

  1. 网络不好,传输不稳定,带宽不够,数据包丢失
  2. 电脑性能问题

TCP概述

TCP是相对于UDP比较稳定的传输协议,存在三次握手,保证连接状态,同时明确区分客户端和服务端之分

TCP服务中需要服务器端先启动,需要监听指定端口,等待客户端连接

TCP操作:Java中提供了两个Socket

  1. 服务端Socket
    java.net.ServerSocket;
    创建对应的ServerSocket开启服务器,等待客户端连接
  2. 客户端Socket
    java.net.Socket
    创建客户端Socket,并且连接服务器,同时将Socket发送给服务器绑定注册

tcp 三次握手四次挥手流程图

Java编程基础之网络编程_服务器_04

Socket客户端

给客户端提供的数据传输符合TCP/IP要求的Socket对象

构造方法Constructor
Socket(String host, int port);
host是服务器IP地址,port对应服务器程序的端口号

成员方法Method
InputStream getInputStream();
获取Socket对象输入字节流,可以从服务器获取对应的数据
InputStream是一个资源,需要在程序退出时关闭

OutputStream getOutputStream();
获取Socket对象输出字节流,可以发送数据到服务器
OutputStream是一个资源,需要在程序退出时关闭

void close();
关闭客户端Socket

void shutdownOutput();
禁止当前Socket发送数据

TCP/IP协议对应的Socket是给予IO流实现的

ServerSocket服务端Socket

在服务器开启Socket服务器

构造方法 Constructor
ServerSocket(int port);
开启ServerSocket服务器,并且明确服务端口

成员方法 Method:
Socket accept();
监听并且连接,得到一个Socket对象,同时该方法是一个阻塞方法,会始终处于一个监听状态
返回的是Socket,即客户端Socket对象,获取到当前Socket对象,相当于获取到客户端连接,同时使用Socket和客户端一致

TCP客户端服务端输入输出关系

Java编程基础之网络编程_客户端_05

服务器代码

流程:

  1. 创建ServerSocket服务器,同时监听指定端口
  2. 通过accept方法获取Socket连接,得到客户端Socket对象
  3. 通过Socket对象,获取InputStream,读取客户端发送数据
  4. 通过Socket对象,获取OutputStream,发送数据给客户端
  5. 关闭服务

package cn.ocean888_tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo {
public static void main(String[] args) throws IOException {
System.out.println("服务端启动");


// 1.创建ServerSocket服务器,同时监听指定端口
ServerSocket serverSocket = new ServerSocket(8888);


// 2.通过accept方法获取Socket连接,得到客户端Socket对象
Socket socket = serverSocket.accept();


// 3.通过Socket对象,获取InputStream,读取客户端发送的数据
InputStream inputStream = socket.getInputStream();


// IO流操作
byte[] buf = new byte[1024];
int length = inputStream.read(buf);
System.out.println(new String(buf, 0, length));


// 4.通过Socket对象,获取OutputStream,发送数据给客户端
OutputStream outputStream = socket.getOutputStream();
String str = "ocean";
outputStream.write(str.getBytes());


// 5.关闭Socket服务同时关闭当前Socket使用的输入字节流和输出字节流
// Closing this socket will also close the socket's InputStream and OutputStream
socket.close();
}
}

客户端代码

流程:

  1. 创建Socket服务,同时明确连接服务器的IP地址和对应端口号
  2. 通过Socket对象,获取对应的OutputStream,发送数据给服务器
  3. 通过Socket对象,获取对应的InputStream,接收服务器发送数据
  4. 关闭连接

package cn.ocean888_tcp;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class ClientDemo {
public static void main(String[] args) throws UnknownHostException, IOException {
System.out.println("客户端启动");


// 1.创建Socket服务,同时明确连接服务器的IP地址和对应端口号
Socket socket = new Socket("169.254.252.105", 8888);


// 2.通过Socket对象,获取对应的OutputStream对象,发送数据给服务器
OutputStream outputStream = socket.getOutputStream();
outputStream.write("client connect".getBytes());

// 3.通过Socket对象,获取对应的InputStream对象,接收服务器发送数据
InputStream inputStream = socket.getInputStream();


byte[] buf = new byte[1024];
int length = inputStream.read(buf);
System.out.println(new String(buf, 0, length));


// 4.关闭服务
socket.close();
}
}

需要首先启动服务端

Java编程基础之网络编程_客户端_06

Java编程基础之网络编程_服务器_07

文件上传实现

Java编程基础之网络编程_客户端_08

客户端

流程:

  1. 创建对应的文件输入字节流操作,可以使用缓存
  2. 启动Socket
  3. 获取Socket输出OutputStream对象,发送数据给服务器
  4. 边读边发
  5. 文件读取结束,发送完毕,关闭客户端

package cn.ocean888_tcp;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;

public class FileClient {
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
// 1.创建缓冲流
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(new File("D:\\JavaCode\\test\\test.jpg")));

// 2.创建socket
Socket socket = new Socket(InetAddress.getLocalHost(), 8848);

// 3.获取socket输出流
OutputStream outputStream = socket.getOutputStream();

int length = -1;
byte[] buf = new byte[1024 * 8];

// 4.读取数据,发送输出,边读边发
while ((length = bufferedInputStream.read(buf)) != -1) {
outputStream.write(buf, 0, length);
}

// 5.关闭连接
socket.close();
}
}

服务端

流程:

  1. 开启服务端,创建ServerSocket服务
  2. 明确文件保存位置,创建对应文件夹的输出缓冲字节流
  3. 读取数据,写入文件
  4. 关闭服务端

package cn.ocean888_tcp;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class FileServer {
public static void main(String[] args) throws IOException {
// 1.开启服务端,创建ServerSocket对象
ServerSocket serverSocket = new ServerSocket(8848);

Socket socket = serverSocket.accept();

// 2.明确保存文件位置,创建对应文件夹缓冲字节流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("D:\\JavaCode\\test\\copy.jpg")));

// 3.获取Socket对应的输入流
InputStream inputStream = socket.getInputStream();

// 4.边读边写
int length = -1;
byte[] buf = new byte[1024 * 8];

while((length = inputStream.read(buf)) != -1) {
bos.write(buf, 0, length);
}

// 5.关闭资源
bos.close();
socket.close();
}
}

运行后

Java编程基础之网络编程_客户端_09

多线程版

解决单线程代码问题:

  1. 保存的文件名是一致的,无法保存多个文件
    使用uuid解决
  2. 服务器代码需要执行多个功能在结束
  3. 服务端代码不可能只有一个上传文件功能
    使用多线程

package cn.ocean888_tcp;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TcpGoodServer {
public static void main(String[] args) throws IOException {
System.out.println("服务器代码启动");

// 1.启动TCP服务端服务
ServerSocket serverSocket = new ServerSocket(8848);

// 2.使用线程池
ExecutorService tp = Executors.newFixedThreadPool(5);

// 3.循环
while (true) {
// 连接客户端
Socket socket = serverSocket.accept();

tp.submit(() -> {
try {
System.out.println(Thread.currentThread().getName());
InputStream inputStream = socket.getInputStream();
String fileName = UUID.randomUUID().toString();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File("D:\\JavaCode\\test\\" + fileName + ".jpg")));

int length = -1;
byte[] buf = new byte[1024 * 8];

while ((length = inputStream.read(buf)) != -1) {
bos.write(buf, 0, length);
}

bos.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
}

运行:先启动服务端在启动多个客户端

Java编程基础之网络编程_客户端_10

Java编程基础之网络编程_服务器_11


举报

相关推荐

0 条评论