网络编程【InetAddress , TCP 、UDP 、HTTP 案例】

day38上

网络编程

InetAddress

理解:表示主机类

一个域名 对应 多个IP地址

java 复制代码
	public static void main(String[] args) throws UnknownHostException {
		
		//获取本机的IP地址
//		InetAddress localHost = InetAddress.getLocalHost();
//		System.out.println(localHost);
		
		//获取域名对应的服务器地址
//		InetAddress byName = InetAddress.getByName("www.baidu.com");
//		System.out.println(byName);
		
		//获取域名对应的所有的服务器地址
		InetAddress[] allByName = InetAddress.getAllByName("www.baidu.com");
		for (InetAddress inetAddress : allByName) {
			System.out.println(inetAddress);
		}      
	}
//输出:www.baidu.com/183.2.172.42
//	   www.baidu.com/183.2.172.185
//是可以通过服务器地址如183.2.172.42去访问的

Scoket

Scoket也叫套接字,其表示的是IP地址和端口号的组合。

网络编程主要就是指Socket编程,网络间的通信其实就是Socket间的通信,数据就通过IO流在两个Scoket间进行传递。

TCP

API:Socket,ServerSocket

客户端(发送一个请求) 服务端(接收到这个请求,给予响应)

案例

1.简单的TCP通信

  1. 编写服务端程序
  2. 编写客户端程序
  3. 客户端向服务端发送请求信息,服务端成功接收
  4. 服务端向客户端发送响应信息,客户端成功接收

2.升级服务端,使其处理多个客户端请求

3.继续优化服务端,让多个客户端的请求无需排队

4.关闭资源-提取工具类

简单的TCP通信
简单的TCP通信理解图

TCP理解图

ps:奇男子去会所按摩

简单的TCP通信

前提:在同一局域网下

先运行服务器

java 复制代码
//服务端
public class Server {

	public static void main(String[] args) throws IOException {
		
		//大堂经理
		ServerSocket server = new ServerSocket(8080);
		
		//18号技师
		//注意:accept()是线程阻塞的方法,该方法会等待客户端的连接成功后才生成一个Socket对象与之交互
		Socket socket = server.accept();
		
		//2.接受来自客户端的数据
//		InputStream in = socket.getInputStream();
//		InputStreamReader isr = new InputStreamReader(in, "GBK");
//		BufferedReader br = new BufferedReader(isr);
        //一步步封装
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));
		String readLine = br.readLine();
		System.out.println(readLine);
		
		//3.向客户端发送数据
		PrintStream ps = new PrintStream(socket.getOutputStream());
		ps.println("18号技师:今年18岁");
		
		br.close();
		ps.close();
		server.close();
	}
}

使用println、BufferedReader

底层识别换行,BufferedReader流的readLine() -- 读取一行

接收是获取的通过转换流再转带缓冲区的流,注意编码格式以防乱码

socket不能随便关闭,最后关闭或者不关闭

java 复制代码
//客户端
public class Client {

	public static void main(String[] args) throws UnknownHostException, IOException {
		
		//注意:关闭流相当于关闭Socket!!!
		
		//奇男子
		Socket socket = new Socket("127.0.0.1", 8080);
		
		//1.向服务端发送数据
		PrintStream ps = new PrintStream(socket.getOutputStream());
		ps.println("奇男子:小妹妹,你多大了?");
		
		//4.接受来自服务端的数据
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));
		String readLine = br.readLine();
		System.out.println(readLine);
		
		ps.close();
		br.close();
		socket.close();
	}
}
简单TCP通信运行图

注意运行显示接受信息

传输文件

类似文件拷贝

较简单TCP通信,使用流不同

java 复制代码
public class Server {

	public static void main(String[] args) throws IOException {
		
		ServerSocket server = new ServerSocket(8080);
		
		Socket socket = server.accept();
		
		BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
		BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.mp4"));
		
		byte[] bs = new byte[1024];
		int len;
		while((len = bis.read(bs)) != -1){
			bos.write(bs, 0, len);
		}
		
		bis.close();
		bos.close();
		server.close();
	}
}
//读取写入文件
java 复制代码
public class Client {
	public static void main(String[] args) throws UnknownHostException, IOException {
		
		Socket socket = new Socket("127.0.0.1", 8080);
		
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("奇男子.mp4"));
        //直接输出流转换为带有缓冲区的,效率更高
		BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
		
		byte[] bs = new byte[1024];
		int len;
		while((len = bis.read(bs)) != -1){
			bos.write(bs, 0, len);
		}
		
		bis.close();
		bos.close();
		socket.close();
	}
}
//读取源文件写出
单聊
单聊

把流放在循环外面,防止每次次循环都new一个流,浪费资源,还有就是没有关闭资源

一对一,你一言我一语

java 复制代码
public class Server {

	public static void main(String[] args) throws IOException {
		
		ServerSocket server = new ServerSocket(8080);
		
		Socket socket = server.accept();
		
		Scanner scan = new Scanner(System.in);
		
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));
		PrintStream ps = new PrintStream(socket.getOutputStream());
		
		while(true){
			String readLine = br.readLine();
			System.out.println(readLine);
			
			ps.println("18号技师:" + scan.next());
		}
		
	}
}
java 复制代码
public class Client {
	public static void main(String[] args) throws UnknownHostException, IOException {
		
		Socket socket = new Socket("127.0.0.1", 8080);
		
		Scanner scan = new Scanner(System.in);
		
		PrintStream ps = new PrintStream(socket.getOutputStream());
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));
		
		while(true){
			
			ps.println("奇男子:" + scan.next());
			
			String readLine = br.readLine();
			System.out.println(readLine);
		}
		
	}
}
优化

单聊一言一语改进:用多线程,一个线程发送、一个线程接受

改进后一个人可以发多条消息

java 复制代码
public class Server {

	public static void main(String[] args) throws IOException {
		
		ServerSocket server = new ServerSocket(8080);
		
		Socket socket = server.accept();
		
		//接收消息
		new ReceiveThread(socket).start();
		
		//发送消息
		Scanner scan = new Scanner(System.in);
		PrintStream ps = new PrintStream(socket.getOutputStream());
		while(true){
			ps.println("18号技师:" + scan.next());
		}
		
	}
}
public class Client {
	public static void main(String[] args) throws UnknownHostException, IOException {
		
		Socket socket = new Socket("127.0.0.1", 8080);
		
		//接收消息
		new ReceiveThread(socket).start();
		
		//发送消息
		Scanner scan = new Scanner(System.in);
		PrintStream ps = new PrintStream(socket.getOutputStream());
		while(true){
			ps.println("奇男子:" + scan.next());
		}
		
	}
}

添加一个接受消息的线程

java 复制代码
//接受的线程
public class ReceiveThread extends Thread{
	
	private Socket socket;
	
	public ReceiveThread(Socket socket) {
		this.socket = socket;
	}

	@Override
	public void run() {
		
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));
			while(true){
				String readLine = br.readLine();
				System.out.println(readLine);
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
			
	}
}
群聊

多线程,发送在子线程,接受在主线程
设想是几个客户端之间互相发送消息,但由于这里使用TCP,而(面向连接)TCP必须通过服务端进行交流,不能这么操作

TCP群聊理解图

服务端连接成功一个就会产生一个Socket,ServerSocket不算进去

这里接受当前客户端的消息再发送给其他客户端,key就直接做成输出流,而不是Socket对象

客户端没有问题,就直接用Client、ReceiveThread,服务端需要更改

简单测试需要多个电脑操作进行群聊,即多个客户端

java 复制代码
public class Server {
	
	public static final ConcurrentHashMap<String, PrintStream> map = new ConcurrentHashMap<>();

	public static void main(String[] args) throws IOException {
		
		ServerSocket server = new ServerSocket(8080);
		
		while(true){
			
			Socket socket = server.accept();
			
			String ip = socket.getInetAddress().toString();
			PrintStream ps = new PrintStream(socket.getOutputStream());
			map.put(ip, ps);
			
			new ServerThread(socket).start();
		}
		
	}
}

添加一个服务端的线程

java 复制代码
public class ServerThread extends Thread{
	
	private Socket socket;
	
	public ServerThread(Socket socket) {
		this.socket = socket;
	}

	@Override
	public void run() {
		
		try {
			//接受当前客户端的消息
			BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));
			while(true){
				String readLine = br.readLine();
				System.out.println(readLine);
				
				//发送给其他客户端消息
				Set<Entry<String,PrintStream>> entrySet = Server.map.entrySet();
				for (Entry<String, PrintStream> entry : entrySet) {
					String ip = entry.getKey();
					PrintStream ps = entry.getValue();
					
					if(!socket.getInetAddress().toString().equals(ip)){
						ps.println(readLine);
					}
				}
			}
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
}

三次握手、四次挥手


UDP

简介

UDP(User Datagram Protocol)用户数据报包协议,UDP和TCP位于同一层-传输层,但它对于数据包的顺序错误或重发没有TCP可靠;UDP是一种面向无连接的通信协议。UDP向应用程序提供一种发送封装的原始IP数据报的方法,并且发送时无需建立连接,不保证可靠数据的传输

UDP理解图

适用:视频聊天

简单的UDP通信

协议的Socket是DatagramSocket

trim()去首尾空格,因为传的数据不到容量就会是空白,超过容量也接收不了

java 复制代码
public class Client01 {

	public static void main(String[] args) throws IOException {
		//注意:7070表示的是自己的端口号,不是对方的端口号
		DatagramSocket socket = new DatagramSocket(7070);
		
		//1.向客户端2发送数据
		byte[] buf = "小桥流水人家".getBytes();
		DatagramPacket p = new DatagramPacket(buf , 0, buf.length, InetAddress.getByName("127.0.0.1"), 8080);
		socket.send(p);
		
		//4.接受来自客户端1的数据
		buf = new byte[1024];
		p = new DatagramPacket(buf , buf.length);
		socket.receive(p);
		System.out.println(new String(buf).trim());
		
		socket.close();
	}
}
public class Client02 {

	public static void main(String[] args) throws IOException {
		
		DatagramSocket socket = new DatagramSocket(8080);
		
		//2.接受来自客户端1的数据
		byte[] buf = new byte[1024];
		DatagramPacket p = new DatagramPacket(buf , buf.length);
		socket.receive(p);
		System.out.println(new String(buf).trim());
		
		//3.向客户端2发送数据
		buf = "古道西风瘦马".getBytes();
		p = new DatagramPacket(buf , 0, buf.length, InetAddress.getByName("127.0.0.1"), 7070);
		socket.send(p);
		
		socket.close();
	}
}

单聊

客户端之间发送消息

java 复制代码
public class Client01 {
	public static void main(String[] args) throws SocketException {
		
		DatagramSocket socket = new DatagramSocket(7070);
		
		new ReceiveThread(socket).start();
		new SendThread("奇男子", "127.0.0.1", 8080, socket).start();
	}
}
public class Client02 {

	public static void main(String[] args) throws SocketException {
		
		DatagramSocket socket = new DatagramSocket(8080);
		
		new ReceiveThread(socket).start();
		new SendThread("小小", "127.0.0.1", 7070, socket).start();
	}
}

添加一个发送线程、一个接收线程

java 复制代码
public class SendThread extends Thread{
	
	private String nickName;
	private String ip;
	private int port;
	private DatagramSocket socket;
	
	public SendThread(String nickName, String ip, int port, DatagramSocket socket) {
		this.nickName = nickName;
		this.ip = ip;
		this.port = port;
		this.socket = socket;
	}
	
	@Override
	public void run() {
		Scanner scan = new Scanner(System.in);
		while(true){
			byte[] buf = (nickName + ":" + scan.next()).getBytes();
			try {
				DatagramPacket p = new DatagramPacket(buf, buf.length, InetAddress.getByName(ip), port);
				socket.send(p);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}
public class ReceiveThread extends Thread{
	
	private DatagramSocket socket;
	
	public ReceiveThread(DatagramSocket socket) {
		this.socket = socket;
	}

	@Override
	public void run() {
		while(true){
			byte[] buf = new byte[1024];
			DatagramPacket p = new DatagramPacket(buf , buf.length);
			try {
				socket.receive(p);
				System.out.println(new String(buf).trim());
			} catch (IOException e) {
				e.printStackTrace();
			}
			
		}
	}
}

TCP vs UDP

TCP UDP
是否连接 面向连接 无面向连接
传输可靠性 可靠 不可靠
应用场合 传输大量数据 少量数据
速度

UDP --- 发短信

TCP --- 打电话

HTTP

查询淘宝商品

需求:获取淘宝商品周边类别

市面上服务器一般都默认为utf-8,设置编码格式,解决乱码

java 复制代码
public class Test01 {

	public static void main(String[] args) throws IOException {
		
		String path = "https://suggest.taobao.com/sug?code=utf-8&q=%E8%80%90%E5%85%8B&callback=cb";
		
		//创建链接对象
		URL url = new URL(path);
		//获取连接对象
        //玩的是他的子类,父类为抽象类
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		
		//设置参数
		connection.setConnectTimeout(5000);//设置连接超时时间
		connection.setReadTimeout(5000);//设置读取数据超时时间
		connection.setDoInput(true);//设置是否允许使用输入流
		connection.setDoOutput(true);//设置是否允许使用输出流
		
		//获取响应状态码
		int code = connection.getResponseCode();
		if(code == HttpURLConnection.HTTP_OK){
			
			BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));
			char[] cs = new char[1024];
			int len;
			while((len = br.read(cs)) != -1){
				System.out.println(new String(cs, 0, len));
			}
			
			
		}else if(code == HttpURLConnection.HTTP_NOT_FOUND){
			System.out.println("页面未找到");
		}
		
	}
}

下载图片

更改流即可【不同数据源用不同的流即可】

java 复制代码
public class Test02 {

	public static void main(String[] args) throws IOException {
		
		String path = "https://wx2.sinaimg.cn/mw690/e2438f6cly1hoo3qpm7vrj21111jk4mn.jpg";
		
		//创建链接对象
		URL url = new URL(path);
		//获取连接对象
		HttpURLConnection connection = (HttpURLConnection) url.openConnection();
		
		//设置参数
		connection.setConnectTimeout(5000);//设置连接超时时间
		connection.setReadTimeout(5000);//设置读取数据超时时间
		connection.setDoInput(true);//设置是否允许使用输入流
		connection.setDoOutput(true);//设置是否允许使用输出流
		
		//获取响应状态码
		int code = connection.getResponseCode();
		if(code == HttpURLConnection.HTTP_OK){
			
			BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());
			BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("金智媛.jpg"));
			byte[] bs = new byte[1024];
			int len;
			while((len = bis.read(bs)) != -1){
				bos.write(bs, 0, len);
			}
			
			bis.close();
			bos.close();
			
		}else if(code == HttpURLConnection.HTTP_NOT_FOUND){
			System.out.println("页面未找到");
		}
		
	}
}

所需学习类

DatagramPacket ---此类表示数据报包

DatagramSocket ---此类用来发送和接受数据报包的套接字

SocketAddress getLocalSocketAddress () 返回此套接字绑定的端点的地 址,如果尚未绑定则返回 null

Voidsend (DatagramPacket p) 从此套接字发送数据报包。

Voidreceive (DatagramPacket p) 从此套接字接收数据报包。

SocketAddress ---抽象类,IP+端口号

总结

1.网络编程

1.1 InetAddress

1.2 TCP

传输文件

单聊、优化单聊

群聊

三次握手、四次挥手

1.3 UDP

单聊

TCP vs UDP

1.4 HTTP

查询淘宝商品

下载图片

相关推荐
Monly21几秒前
Java(若依):修改Tomcat的版本
java·开发语言·tomcat
Ttang232 分钟前
Tomcat原理(6)——tomcat完整实现
java·tomcat
钱多多_qdd13 分钟前
spring cache源码解析(四)——从@EnableCaching开始来阅读源码
java·spring boot·spring
waicsdn_haha15 分钟前
Java/JDK下载、安装及环境配置超详细教程【Windows10、macOS和Linux图文详解】
java·运维·服务器·开发语言·windows·后端·jdk
biter008821 分钟前
opencv(15) OpenCV背景减除器(Background Subtractors)学习
人工智能·opencv·学习
Q_192849990625 分钟前
基于Spring Boot的摄影器材租赁回收系统
java·spring boot·后端
Code_流苏28 分钟前
VSCode搭建Java开发环境 2024保姆级安装教程(Java环境搭建+VSCode安装+运行测试+背景图设置)
java·ide·vscode·搭建·java开发环境
青灯文案131 分钟前
前端 HTTP 请求由 Nginx 反向代理和 API 网关到后端服务的流程
前端·nginx·http
禁默1 小时前
深入浅出:AWT的基本组件及其应用
java·开发语言·界面编程
Cachel wood1 小时前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架