Java中的网络编程(UDP、TCP/IP协议)

1.网络编程概述

1.1 C/S和B/S

C/S

客户端——服务器软件结构
服务提供商给予用户服务需要准备的内容(如:本地软件更新)

B/S

浏览器——服务器软件结构
服务提供商只要提供数据服务以及前端数据展示方式。

1.2 网络通信协议

协议

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

常见的协议:

应用层	HTTP、HTTPS、FTP、SMTP、SNMP、DNS
传输层	TCP、UDP
网络层	JCMP、IGMP、IP、ARP、PARP
数据链路层	Wi-Fi、GPS、以太网
物理层	以太网、调制解调器

1.3 UDP和TCP/IP区别

UDP用户数据报协议

类似于广播
面向无连接,数据传递不算特别安全
因为无连接,传输速度快
因为无连接,数据传递存在丢包问题
UDP没有客户端和服务器端区别,都可以作为发送端和接收端
UDP协议使用场景:直播、游戏

TCP/IP传输控制协议

面向连接,数据传递较为安全
因为有连接,所以传递速度较慢
但数据传递有保障
TCP/IP协议是有明确的客户端和服务器端概念
TCP/IP协议使用场景:客户端登陆,数据下载,文件传输

1.4 网络编程的三要素

(1)协议

两个在有网络的情况下的计算机数据传递,都需要对应的协议来完成

(2)IP地址

Internet Protocol Address
当前计算机在网络中的一个地址编号,类似于手机号码
IPv4是一个32位的二进制数,通常展示效果是a.b.c.d 如:192.168.1.1。abcd各代表0~255的数字,目前已使用完。

IPv6是足够使用。
128位地址长度,16字节一组,8组,0x0 ~ 0xFFFF

(3)端口号

端口号是当前应用程序在计算机中的一个编号。可以让计算机明确知道,当前的数据是给予哪一个程序使用,或者数据从哪一个程序出现。
端口号是一个short类型 0~65535
0~1024不能用于自定义端口号使用,特定的系统端口号。

2.IP类

SUN公司提供给开发使用的IP地址类(InetAddress)
常用方法

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

代码演示

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

/*
 * IP类演示
 */
public class Demo1 {
	public static void main(String[] args) throws UnknownHostException {
		InetAddress localHost = InetAddress.getLocalHost();
		System.out.println(localHost);
		
		InetAddress byName = InetAddress.getByName("DESKTOP-M89SDP7");
		System.out.println(byName);
		
		InetAddress byName2 = InetAddress.getByName("www.4399.com");
		System.out.println(byName2);
		
		System.out.println("----------------------------------");
		
		InetAddress[] allByName = InetAddress.getAllByName("www.baidu.com");
		for (InetAddress inetAddress : allByName) {
			System.out.println(inetAddress);
		}
		
		System.out.println("----------------------------------");
		InetAddress[] allByName1 = InetAddress.getAllByName("www.taobao.com");
		for (InetAddress inetAddress : allByName1) {
			System.out.println(inetAddress);
		}
		
		System.out.println("----------------------------------");
		InetAddress[] allByName2 = InetAddress.getAllByName("www.jd.com");
		for (InetAddress inetAddress : allByName2) {
			System.out.println(inetAddress);
		}
	}
}

3.UDP协议

3.1 UDP数据传输方式

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:当前字节缓冲数组的容量

3.2发送端流程

流程

创建UDP服务器对应的发送端Socket
准备对应数据包,需要带有指定数据
发送数据包 send
关闭UDP发送端

代码演示

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("发送端启动");
		// 创建对应的Socket
		DatagramSocket socket = new DatagramSocket();
		
		// 准备数据包
		byte[] bytes = "今天中午吃蒸羊羔...".getBytes();
		DatagramPacket packet = new DatagramPacket(bytes,  // 字节数组数据
				bytes.length,  // 字节数组数据长度
				InetAddress.getLocalHost(),  // 指定接收端IP地址
				8848); // 8848对应端口号
		
		// 发送数据包
		socket.send(packet);
		// 关闭UDP发送端
		socket.close();
	}
}

3.3接收端流程

流程

打开UDP服务,并且监听指定端口
创建新的空数据包
通过Socket接受数据
关闭UDP服务接收端

代码演示

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveDemo1 {
	public static void main(String[] args) throws IOException {
		// 创建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();
		
	}
}

3.4UDP数据传递丢失问题

网络不够好,稳定性不行,带宽不够
电脑性能不好

以上都会导致数据传递丢失

3.5FeiQ

网络传输都有自己的传输规格,如果软件接收到的数据是自己的规格,那么可以读取数据,否则丢弃!!
如FeiQ:

version:time:sender:ip:flag:content
版本:时间:发送者名字:发送人IP:标记:内容
数据是一个String类型
而且使用的协议是UDP协议

代码演示

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

public class FeiQ {
	public static void main(String[] args) throws IOException {
		DatagramSocket socket = new DatagramSocket();
		
		//getData方法,将字符串数据转换为指定格式
		String data = getData("Welcome to Java World!!!");
		DatagramPacket datagramPacket = new DatagramPacket(data.getBytes(), data.getBytes().length
				, InetAddress.getByName("192.168.31.255"), 2425);
		
		socket.send(datagramPacket);
		
		socket.close();
		
	}
	
	/**
	 * 传入数据,转换成FeiQ可以识别的数据
	 * version:time:sender:ip:flag:content
	 * 
	 * @param message 字符串类型内容
	 * @return 符合FeiQ格式要求的字符串
	 */
	public static String getData(String message) {
		StringBuilder stb = new StringBuilder();
		
		stb.append("1.0:");
		stb.append(System.currentTimeMillis() + ":");
		stb.append("Anonymous:");
		stb.append("10.1.1.1:");
		stb.append("32:");
		stb.append(message);
		
		return stb.toString();
	} 
}

4.TCP协议

4.1 TCP概述

TCP相对于UDP比较稳定,存在三次握手机制,保证连接状态,同时有明确的客户端和服务器之分
TCP服务中需要服务器端先启动,需要监听指定端口,等待客户端连接。
客户端主动连接服务器,和服务器连接之后,才可以进行数据交互,服务器不能主动连接客户端。

对于TCP,Java中提供了两个Socket

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

三次握手机制
在这里插入图片描述

4.2 客户端Socket

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

Socket(String host, int port);
	host:是服务器IP地址
	port:对应服务器程序的端口号
	通过指定的【服务器IP地址】和【端口号】,获取TCP连接对象

成员方法

InputStream getInputStream();
	获取Socket对象输入字节流,可以【从服务器获取】对应的数据
	InputStream是一个资源,需要在程序退出时关闭
OutputStream getOutputStream();
	获取Socket对象输出字节流,可以【发送数据】到服务器
	须在退出时关闭
void close();
	关闭客户端Socket
void shutdownOutput();
	禁止当前Socket发送数据

TCP/IP协议对应的Socket是基于IO流实现的。

4.3 服务端Socket(ServerSocket)

构造方法

ServeSocket(int port);
	开启ServeSocket服务器,并且明确当前服务端口是谁

成员方法

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

4.4 TCP协议演示

在这里插入图片描述

4.4.1服务器流程

流程:

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

代码演示:

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

/*
流程:
	1. 创建ServerSocket服务器,同时监听指定端口
	2. 通过accept方法获取Socket连接,得到客户端Socket对象
	3. 通过Socket对象,获取InputStream,读取客户端发送数据
	4. 通过Socket对象,获取OutputStream,发送数据给客户端
	5. 关闭服务 
 */
public class TcpServer1 {
	public static void main(String[] args) throws IOException {
		System.out.println("服务器启动");
		System.out.println("-----------------------");
		// 1. 创建ServerSocket服务器,同时监听指定端口
		ServerSocket serverSocket = new ServerSocket(8848);
	
		// 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 = "欢迎来到德莱联盟";
		
		outputStream.write(str.getBytes());
		
		// 5. 关闭Socket服务 同时关闭当前Socket使用的输入字节流和输出字节流	
		// Closing this socket will also close the socket's InputStream and OutputStream. 
		socket.close();	
	}
}
4.4.2客户端流程

流程:

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

代码演示

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

/*
流程:
	1. 创建Socket服务,同时明确连接服务器的IP地址和对应端口号
	2. 通过Socket对象,获取对应的OutputStream对象,发送数据给服务器
	3. 通过Socket对象,获取对应的InputStream对象,接收服务器发送数据
	4. 关闭服务
 */
public class TcpClient1 {
	public static void main(String[] args) throws UnknownHostException, IOException {
		System.out.println("客户端启动");
		System.out.println("------------------------");
		// 1. 创建Socket服务,同时明确连接服务器的IP地址和对应端口号
		Socket socket = new Socket("192.168.31.154", 8848);
		
		// 2. 通过Socket对象,获取对应的OutputStream对象,发送数据给服务器
		OutputStream outputStream = socket.getOutputStream();
		
		outputStream.write("你好服务器!!!".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();
	}
}

4.5 文件上传操作

4.5.1分析过程

在这里插入图片描述

4.5.2 客户端程序

流程:

(1)创建对应文件的输入字节流操作,用缓冲
(2)启动Socket
(3)获取Socket输出OutputStream对象,发送数据给服务器
(4)边读边发,而不是读取完再统一发送
(5)档文件读取结束时,发送完毕,关闭客户端

代码演示:

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;

/*
流程:
	1. 创建对应文件的输入字节流操作,这里可以使用缓冲
	2. 启动Socket,
	3. 获取Socket输出OutputStream对象,发送数据给服务器
	4. 边读边发
	5. 当文件读取结束,发送完毕,关闭客户端
 */
public class TcpClient {
	public static void main(String[] args) throws IOException {
		// 1. 创建对应文件的输入字节流操作,这里可以使用缓冲
		BufferedInputStream bis = new BufferedInputStream(
				new FileInputStream(new File("D:/aaa/1.mp4")));
		
		// 2. 启动Socket
		Socket socket = new Socket(InetAddress.getLocalHost().getHostAddress(), 8848);
		
		// 3. 获取Socket输出OutputStream对象,发送数据给服务器
		OutputStream outputStream = socket.getOutputStream();
		
		int length = -1;
		byte[] buf = new byte[1024 * 8];
		
		
		// 4. 读取数据,发送数据
		while ((length = bis.read(buf)) != -1) {
			outputStream.write(buf, 0, length);
		}
		
		// 5. 关闭资源
		socket.close();
		bis.close();
	}
}
4.5.3服务端程序

流程:

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

代码演示:

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;

/*
流程:
	1. 开启服务端服务,创建ServerSocket对象
	2. 明确保存文件的位置,创建对应文件夹的输出缓冲字节流
	3. 读取数据,写入文件
	4. 关闭服务器
 */
public class TcpServer {
	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:/aaa/temp.mp4")));
		
		// 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();
	}
}
4.5.4 目前服务端代码问题
(1)保存的文件名都是一致的,无法保存多个文件夹。
(2)服务端代码肯定不能执行完一个上传功能就结束
(3)服务端代码不可能只有一个上传文件功能
(4)多线程
发布了14 篇原创文章 · 获赞 21 · 访问量 5524

猜你喜欢

转载自blog.csdn.net/qq_41986648/article/details/104658444