第14章 网络编程

课程回顾

多线程,
创建线程的三种方式:
①继承Thread类
②实现Runnable接口
③实现Callable接口 call 可以返回值, FutrueTask, Thread
线程同步:
①synchronized 同步代码块 同步方法
②Lock lock.lock() lock.unlock();
死锁:
①锁的嵌套使用
②锁的顺序不一致
生产者和消费者模型
生产者和消费者操作的是同一空间;
wait和notify实现同步
解决多次生产多次消费:
①: 自旋锁 while
②: Lock ReentrentLock
③: Condition 条件通知, 消费者通知生产者, 生产者线程通知消费者线程
线程池:
①: 无界线程池
②: 有界线程池
③: 单一线程池
一次创建多个线程, 执行多个任务.提高执行效率; 线程池: Set 集合 再有阻塞队列: LinkedBlockingQueue

网络通信协议简介

TCP/IP : Transmission Control Protocol 传输控制协议 / Internet Protocol 网际协议

在这里插入图片描述
在这里插入图片描述

应用层协议
HTTP: 超文本传输协议 互联网的重要协议
FTP: 文件传输协议
SMTP: 简单邮件传输协议
DNS: 域名解析: 把域名 绑定到 ip地址
RPC: remote 远程 procedure 过程 Call 调用协议
SNM: 网络相关

传输层协议
TCP: 面向连接的协议, 必须连接之后才可以通信; 打电话
UDP: 面向无连接的协议, 对讲机
广播协议: MultiBroadCast

InetAddress类的用法

网络通信的基础是: 每个连接到网络的主机要有一个IP地址, IP地址v4, v6版本; IP地址用InetAddress类分装. InetAddress表示一个IP地址.

Inet4Address 该类表示Internet协议版本4(IPv4)地址。  
Inet6Address 该类表示Internet协议版本6(IPv6)地址。  
InetAddress 此类表示Internet协议(IP)地址。  

案例:

package com.hanker1;

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

public class INetAddressDemo {

	public static void main(String[] args) throws IOException {
		InetAddress address = InetAddress.getByName("www.taobao.com");
		System.out.println("主机名: "+address.getHostName());
		System.out.println("IP地址:"+address.getHostAddress());
		System.out.println("是否可以访问: "+address.isReachable(3000));
		
		InetAddress localHost = InetAddress.getLocalHost();
		System.out.println("本地主机名称:"+localHost.getHostName());
		System.out.println("本地主机的IP:"+localHost.getHostAddress());
	}
}

TCP通信

面向连接的协议, 主机之间必须建立连接才可以通信; TCP通信的两个核心类:
①: ServerSocket 服务器套接字
②: Socket 客户端 插座
在这里插入图片描述

ServerSocket接收到客户端Socket连接之后, 返回的是一个Socket对象, 该Socket对象和当前客户端进行通信; ServerSocket继续等待新连接;
创建ServerSocket需要提供一个端口号: 通信基于该端口号, 火车站是一个服务器, 售票窗口可以理解为端口号: 1号窗口 2号窗口.
在这里插入图片描述

端口号:最大到 65535, 1000以下说是系统占用的, 我们可以使用 10000以上.

ServerSocket和客户端建立连接的过程:

在这里插入图片描述

贯穿的案例: 客户端和服务器进行聊天的工具.

Version 1: 连接到服务器

客户端和服务器连接, 服务器发送一个消息告诉客户端连接成功.

package com.hanker1;

import java.io.IOException;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
//1. 客户端和服务器建立连接
//2. 服务器发送一个信息到客户端
public class MyServer1 {

	public static void main(String[] args) throws IOException {
		System.out.println("服务器启动成功,等待连接......");
		ServerSocket serverSocket = new ServerSocket(8888);
		//等待连接, accept接受的意思,当运行到该方法,出现线程阻塞
		//服务器通过该Socket对象和客户端进行通信,  ServerSocket只接受新连接
		Socket socket = serverSocket.accept();
		//获取连接的IP地址
		String addr = socket.getInetAddress().getHostAddress();
		System.out.println(addr+"连接到服务器....小伙子你跑不了");
		//获取输出流
		OutputStream os = socket.getOutputStream();
		//获取字符串的字节数组
		byte[] bytes = "元旦快乐".getBytes();
		//向输出流写字节数组
		os.write(bytes);
		//关闭连接
		os.close();
		serverSocket.close();
	}
}
//================================
package com.hanker1;
import java.io.InputStream;
import java.net.Socket;
public class MyClient1 {
	public static void main(String[] args) throws Exception {
		//1.创建Socket客户端对象
		Socket socket = new Socket("localhost", 8888);
		//2.获取服务器发送的信息
		InputStream inputStream = socket.getInputStream();
		byte[] b = new byte[1024];
		int len = inputStream.read(b);
		System.out.println("读取的字节数:" + len);
		System.out.println("服务器说:"+ new String(b,0,len));
		inputStream.close();
		socket.close();
	}
}

Version2 : 双向通信

服务器向客户端发送消息, 客户端向服务器发送信息

package com.hanker1;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServer2 {

	public static void main(String[] args) throws Exception {
		//0.提示
		System.out.println("服务器启动成功.......");
		//1.建立服务器端对象
		ServerSocket serverSocket = new ServerSocket(8080);
		//2.等待连接
		Socket socket = serverSocket.accept();
		//3.获取连接的IP地址
		String ip = socket.getInetAddress().getHostAddress();
		System.out.println(ip+"连接到服务器..");
		//4.向客户端发送一个消息: 字节流转换成字符流
		OutputStream os = socket.getOutputStream();
		//把字节流转换成字符流
		OutputStreamWriter  osw =new OutputStreamWriter(os);
		//可以直接写字符串:不用再转换成字节数组
		osw.write("2020元旦快乐");
         osw.write("\r\n".getBytes());
		osw.flush();//注意刷出缓冲区
		//5.接收客户端的消息
		InputStream inputStream = socket.getInputStream();//字节流
		//把字节流转换成字符流
		InputStreamReader reader = new InputStreamReader(inputStream);
		//转成缓冲流: 因为可以一次读取一行,而且不用char数组
		BufferedReader br = new BufferedReader(reader);
		//一次读取一行
		String line = br.readLine();
		System.out.println("客户端说:"+line);
		//6.关闭输出流
		osw.close();
		serverSocket.close();
	}
}
/*
OutputStream out = socket.getOutputStream();
 存在的问题: 
 1.只能发送字节数组
 2.没有换行标记
 3.不能自动刷新
怎么解决?
PrintWriter out = new PrintWriter( ,true);
1.可以直接发送字符串
2.可以发送换行符  out.println
3.可以自动刷新
*/
//===============================
package com.hanker1;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

public class MyClient2 {

	public static void main(String[] args) throws Exception {
		//1.创建客户端的对象
		Socket socket = new Socket("localhost",8080);
		//2.接收服务器发送的消息
		InputStream inputStream = socket.getInputStream();
		InputStreamReader  isr = new InputStreamReader(inputStream);
		char cbuf[] = new char[1024];
		int len = isr.read(cbuf);
		System.out.println("服务器说:"+new String(cbuf,0,len));
		
		//3.发送消息
		OutputStream outputStream = socket.getOutputStream();
		PrintWriter pw = new PrintWriter(outputStream);
		pw.println("哥们不快乐,加班学习.....");
		pw.close();
		socket.close();
	}
}

Version2 : 服务器向客户端发送消息, 客户端向服务器发送信息

package com.hanker1;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class MyServer2 {

	public static void main(String[] args) throws Exception {
		//0.提示
		System.out.println("服务器启动成功.......");
		//1.建立服务器端对象
		ServerSocket serverSocket = new ServerSocket(8080);
		//2.等待连接
		Socket socket = serverSocket.accept();
		//3.获取连接的IP地址
		String ip = socket.getInetAddress().getHostAddress();
		System.out.println(ip+"连接到服务器..");
		//4.向客户端发送一个消息: 字节流转换成字符流
		OutputStream os = socket.getOutputStream();
		//把字节流转换成字符流
		OutputStreamWriter  osw =new OutputStreamWriter(os);
		//可以直接写字符串:不用再转换成字节数组
		osw.write("2020元旦快乐");
		osw.flush();//注意刷出缓冲区
		//5.接收客户端的消息
		InputStream inputStream = socket.getInputStream();//字节流
		//把字节流转换成字符流
		InputStreamReader reader = new InputStreamReader(inputStream);
		//转成缓冲流: 因为可以一次读取一行,而且不用char数组
		BufferedReader br = new BufferedReader(reader);
		//一次读取一行
		String line = br.readLine();
		System.out.println("客户端说:"+line);
		//6.关闭输出流
		osw.close();
		serverSocket.close();
	}
}
//===============================
package com.hanker1;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;

public class MyClient2 {

	public static void main(String[] args) throws Exception {
		//1.创建客户端的对象
		Socket socket = new Socket("localhost",8080);
		//2.接收服务器发送的消息
		InputStream inputStream = socket.getInputStream();
		InputStreamReader  isr = new InputStreamReader(inputStream);
		char cbuf[] = new char[1024];
		int len = isr.read(cbuf);
		System.out.println("服务器说:"+new String(cbuf,0,len));
		
		//3.发送消息
		OutputStream outputStream = socket.getOutputStream();
		PrintWriter pw = new PrintWriter(outputStream);
		pw.println("哥们不快乐,加班学习.....");
		pw.close();
		socket.close();
	}
}

Version3 : 发送动态消息

服务器向客户端发送消息, 客户端向服务器发送动态信息: 可以从控制台输入

package com.hanker1;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

//version3: 可以不断的接收用户的消息,回固定消息
public class MyServer3 {

	public static void main(String[] args) throws Exception {
		ServerSocket serverSocket = new ServerSocket(8080);
		System.out.println("服务器启动成功......");
		Socket socket = serverSocket.accept();
		BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		//自动刷出缓冲区
		PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
		//返回固定消息
		out.println("2020元旦快乐,新年吉祥...");
		//接收消息
		String line = null;
		while( (line = reader.readLine())!=null) {
			System.out.println("客户端说:" +line);
		}
		//关闭
		out.close();
		reader.close();
		serverSocket.close();
	}
}
//==============================
package com.hanker1;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class MyClient3 {

	public static void main(String[] args) throws Exception {
		//1. 连接到服务器
		Socket socket = new Socket("localhost",8080);
		BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		System.out.println("服务器说:"+reader.readLine());
		//发消息
		PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
		//实现从控制台输入消息
		Scanner input = new Scanner(System.in);
		while(true) {
			String word = input.next();
			if(word.equals("over")) {
				break;
			}
			out.println(word);//把输入的话发送到服务器
		}
		input.close();
		out.close();
		socket.close();
	}
}

Version4: 聊天

package com.hanker1;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

//version4: 实现聊天
public class MyServer4 {

	public static void main(String[] args) throws Exception {
		ServerSocket serverSocket = new ServerSocket(8080);
		System.out.println("服务器启动成功......");
		Socket socket = serverSocket.accept();
		System.out.println(socket.getInetAddress().getHostAddress()+"连接到服务器");
		BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		//自动刷出缓冲区
		PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
		//接收消息
		String line = null;
		//输入消息
		Scanner input = new Scanner(System.in);
		while( (line = reader.readLine())!=null) {
			System.out.println("客户端说:" +line);
			System.out.print("请你发言:");
			String word = input.next();
			out.println(word);
		}
		//关闭
		input.close();
		out.close();
		reader.close();
		serverSocket.close();
	}
}
//======================================
package com.hanker1;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class MyClient4 {

	public static void main(String[] args) throws Exception {
		//1. 连接到服务器
		Socket socket = new Socket("localhost",8080);
		BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		//发消息
		PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
		//实现从控制台输入消息
		Scanner input = new Scanner(System.in);
		while(true) {
			System.out.print("请输入向服务器发送的信息:");
			String word = input.next();
			if(word.equals("over")) {
				break;
			}
			out.println(word);//把输入的话发送到服务器
			String line = reader.readLine();
			System.out.println("服务器说:"+line);
		}
		input.close();
		out.close();
		socket.close();
	}
}

以上只能接收一个客户端连接, 再次启动客户端就出现线程阻塞.; 所以要加入多线程支持.

Version5: 多线程聊天

package com.hanker1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
//线程类
class MyThread implements Runnable {
	private Socket socket;

	public MyThread(Socket socket) {
		this.socket = socket;
	}

	@Override
	public void run() {
		Scanner input = null;
		PrintWriter out = null;
		BufferedReader reader = null;
		try {
			// 获取当前线程名
			String name = Thread.currentThread().getName();
			System.out.println(socket.getInetAddress().getHostAddress() + "连接到服务器,线程:" + name);
			reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			// 自动刷出缓冲区
			out = new PrintWriter(socket.getOutputStream(), true);
			// 接收消息
			String line = null;
			// 输入消息
			input = new Scanner(System.in);
			while ((line = reader.readLine()) != null) {
				System.out.println("客户端说:" + line);
				System.out.print("请你发言:");
				String word = input.next();
				out.println(word);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				// 关闭
				input.close();
				out.close();
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}

//version5: 多线程实现聊天
public class MyServer5 {

	public static void main(String[] args) throws Exception {
		ServerSocket serverSocket = new ServerSocket(8080);
		System.out.println("服务器启动成功......");
		while(true) {
			Socket socket = serverSocket.accept();//获取连接
			MyThread myThread = new MyThread(socket);//创建线程对象
			new Thread(myThread).start();//启动线程
		}

	}

}
//==================客户端======================
package com.hanker1;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;

public class MyClient5 {

	public static void main(String[] args) throws Exception {
		//1. 连接到服务器
		Socket socket = new Socket("localhost",8080);
		BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		//发消息
		PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
		//实现从控制台输入消息
		Scanner input = new Scanner(System.in);
		while(true) {
			System.out.print("请输入向服务器发送的信息:");
			String word = input.next();
			if(word.equals("over")) {
				break;
			}
			out.println(word);//把输入的话发送到服务器
			String line = reader.readLine();
			System.out.println("服务器说:"+line);
		}
		input.close();
		out.close();
		socket.close();
	}
}

在这里插入图片描述

Version6: 弹幕器

package com.hanker1;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
//线程类
class MyThread2 implements Runnable {
	private Socket socket;

	public MyThread2(Socket socket) {
		this.socket = socket;
	}

	@Override
	public void run() {
		Scanner input = null;
		PrintWriter out = null;
		BufferedReader reader = null;
		try {
			// 获取当前线程名
			String name = Thread.currentThread().getName();
			System.out.println(socket.getInetAddress().getHostAddress() + "连接到服务器,线程:" + name);
			reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			// 自动刷出缓冲区
			out = new PrintWriter(socket.getOutputStream(), true);
			// 接收消息
			String line = null;
			// 输入消息
			input = new Scanner(System.in);
			while ((line = reader.readLine()) != null) {
				System.out.println("客户端说:" + line);				
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				// 关闭
				input.close();
				out.close();
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

}

//version6: 多线程弹幕器,只接收不发送
public class MyServer6 {

	public static void main(String[] args) throws Exception {
		ServerSocket serverSocket = new ServerSocket(8080);
		System.out.println("服务器启动成功......");
		while(true) {
			Socket socket = serverSocket.accept();//获取连接
			MyThread2 myThread = new MyThread2(socket);//创建线程对象
			new Thread(myThread).start();//启动线程
		}

	}

}
//=============客户端=============
package com.hanker1;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;
//Version6 弹幕器,只发送不接收
public class MyClient6 {

	public static void main(String[] args) throws Exception {
		//1. 连接到服务器
		Socket socket = new Socket("192.168.1.3",8080);
		BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		//发消息
		PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
		//实现从控制台输入消息
		Scanner input = new Scanner(System.in);
		while(true) {
			System.out.print("请输入向服务器发送的信息:");
			String word = input.next();
			if(word.equals("over")) {
				break;
			}
			out.println(word);//把输入的话发送到服务器
		}
		input.close();
		out.close();
		socket.close();
	}
}

在这里插入图片描述

转换大写字母

package tcp;
import java.io.BufferedReader; 

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class TransServer {
public static void main(String[] args) throws IOException {
	/*
	* 转换服务端。
	* 分析:
	* 1,创建serversocket服务。
	* 2,获取socket对象。
	* 3,源:socket,读取客户端发过来的需要转换的数据。
	* 4,目的:显示在控制台上。
	* 5,将数据转成大写发给客户端。
	*/
	//1,创建ServerSocket对象
	ServerSocket ss = new ServerSocket(10004);
	//2,获取socket对象。
	Socket s = ss.accept();
	//获取ip.
	String ip = s.getInetAddress().getHostAddress();
	System.out.println(ip+"......connected");
	//3,获取socket读取流,并装饰。
	BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
	//4,获取socket的输出流,并装饰。
	PrintWriter out = new PrintWriter(s.getOutputStream(),true);
	String line = null;
	while((line=bufIn.readLine())!=null){
	System.out.println(line);
	//out.print(line.toUpperCase());
	out.print(line.toUpperCase()+"\r\n");
	out.flush();
	}
	s.close();
	ss.close();
	}
}
//========================
package tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;

public class TransClient {
	public static void main(String[] args) throws UnknownHostException, IOException {
		/*
		 * 客户端思路:
		 * 1,需要先有socket端点。 
		 * 2,客户端的数据源:键盘。 
		 * 3,客户端的目的:socket.
		 * 4,接收服务端的数据,源:socket。
		 * 5,将数据显示在打印出来:目的:控制台. 
		 * 6,在这些流中操作的数据,都是文本数据。
		 * 转换客户端: 
		 * 1,创建socket客户端对象。 
		 * 2,获取键盘录入。 
		 * 3,将录入的信息发送给socket输出流。
		 */
		// 1,创建socket客户端对象。
		Socket s = new Socket("localhost", 10004);
		// 2,获取键盘录入。
		//BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
		Scanner bufr = new Scanner(System.in);
		// 3,socket输出流。
		// new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
		PrintWriter out = new PrintWriter(s.getOutputStream(), true);
		// 4,socket输入流,读取服务端返回的大写数据
		BufferedReader bufIn = new BufferedReader(new InputStreamReader(s.getInputStream()));
		String line = null;
		while ((line = bufr.next()) != null) {
			if ("over".equals(line))
				break;
			// out.print(line+"\r\n");
			// out.flush();
			out.println(line);
			// 读取服务端发回的一行大写数。
			String upperStr = bufIn.readLine();
			System.out.println(upperStr);
		}
		s.close();
	}
}

图片上传

package tcp;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;

public class UploadTask implements Runnable {
	private static final int SIZE = 1024 * 1024 * 2;
	private Socket s;
	public UploadTask(Socket s) {
		this.s = s;
	}
	@Override
	public void run() {
		int count = 0;
		String ip = s.getInetAddress().getHostAddress();
		System.out.println(ip + "连接到服务器...");
		try {
			// 读取客户端发来的数据。
			InputStream in = s.getInputStream();
			// 将读取到数据存储到一个文件中。
			File dir = new File("c:\\pic");
			if (!dir.exists()) {
				dir.mkdirs();
			}
			File file = new File(dir, ip + ".jpg");
			// 如果文件已经存在于服务端
			while (file.exists()) {
				file = new File(dir, ip + "(" + (++count) + ").jpg");
			}
			FileOutputStream fos = new FileOutputStream(file);
			byte[] buf = new byte[1024];
			int len = 0;
			while ((len = in.read(buf)) != -1) {
				fos.write(buf, 0, len);
				if (file.length() > SIZE) {
					System.out.println(ip + "文件体积过大");
					fos.close();
					s.close();

					System.out.println(ip + "...." + file.delete());
					return;
				}
			}
			// 获取socket输出流,将上传成功字样发给客户端。
			OutputStream out = s.getOutputStream();
			out.write("上传成功".getBytes());
			fos.close();
			s.close();
		} catch (IOException e) {
		}
	}
}
//=========服务器端============
package tcp;

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

public class UploadPicServer {
	public static void main(String[] args) throws IOException {
		// 创建tcp的socket服务端。
		ServerSocket ss = new ServerSocket(10006);
		while (true) {
			Socket s = ss.accept();// 获取客户端。
			new Thread(new UploadTask(s)).start();
		}
	}
}
//===============客户端====================
package tcp;

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

public class UploadPicClient {

	public static void main(String[] args) throws UnknownHostException, IOException {
		//1,创建客户端socket。
		Socket s = new Socket("192.168.1.100", 10006);
		//2,读取客户端要上传的图片文件。
		FileInputStream fis = new FileInputStream("c:\\0.bmp");
		//3,获取socket输出流,将读到图片数据发送给服务端。
		OutputStream out = s.getOutputStream();
		byte[] buf = new byte[1024];

		int len = 0;
		while ((len = fis.read(buf)) != -1) {
			out.write(buf, 0, len);
		}
		//告诉服务端说:这边的数据发送完毕。让服务端停止读取。
		s.shutdownOutput();
		//读取服务端发回的内容。
		InputStream in = s.getInputStream();
		int lenIn = in.read(buf);
		String text = new String(buf, 0, lenIn);
		System.out.println(text);
		fis.close();
		s.close();
	}
}

文件上传

package net;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

//文件上传服务器
public class FileUploadServer {

	public static void main(String[] args) throws Exception {
		//1.创建服务器对象
		ServerSocket server = new ServerSocket(9001);
		//2.接收客户端连接
		System.out.println("文件上传服务器启动中....");
		Socket socket = server.accept();
		System.out.println(socket.getInetAddress().getHostAddress()+"连接到服务器.");
		//3.获取输入流对象
		BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		//4.创建输出流对象--把读取到的内容写到文件
		BufferedWriter writer=new BufferedWriter(new FileWriter("d:\\server.txt"));
		//5.循环读取
		String line = null;
		while( (line=reader.readLine())!=null ){
			writer.write(line);
			writer.newLine();
		}
		//6.获取Socket输出流对象
		PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
		//7.告诉客户端上传成功
		out.println("恭喜,上传成功.");
		//8.关闭流
		writer.close();
		out.close();
		reader.close();
		socket.close();
		server.close();
	}

}
//==============================
package net;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class FileUploadClient {

	public static void main(String[] args)  throws Exception{
		//1.创建Socket客户端对象
		Socket socket=new Socket("localhost",9001);
		//2.获取socket对象的输出流
		PrintWriter out=new PrintWriter(socket.getOutputStream(),true);
		//3.以文件作为输入流
		BufferedReader fileReader=new BufferedReader(new FileReader("E:\\1.java基础\\第0章\\笔记.txt"));
		//4.边读边上传
		String line = null;
		while( (line=fileReader.readLine()) !=null ){
			out.println(line);
		}
		//5.告诉服务器上传结束
		socket.shutdownOutput();
		//6.获取服务器返回的消息
		BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
		String answer=reader.readLine();
		System.out.println(answer);
		reader.close();
		fileReader.close();
		out.close();
		socket.close();
	}

}

UDP通信

面向无连接的协议, 不需要长连接方式. UDP编程需要两个类:

DatagramPacket 该类表示数据报包。  发送或接收的报文
DatagramSocket 此类表示用于发送和接收数据报数据包的套接字。  

DatagramSocket可以发送数据还可以接收数据, 接受和发送的是DatagramPacket数据报文.
在这里插入图片描述

DatagramPacket的构造方法:
在这里插入图片描述

数据报文的格式:
在这里插入图片描述

在这里插入图片描述

单向通信

package com.hanker2;

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

public class UDPServer {

	public static void main(String[] args) throws Exception {
		//1. 创建发送端
		DatagramSocket socket = new DatagramSocket();
		//2.创建数据包
		String str = "2020元旦快乐";
		DatagramPacket packet =new  DatagramPacket(
				str.getBytes(),
				str.getBytes().length,
				InetAddress.getByName("localhost"),
				8888);
		//3.发送数据包
		socket.send(packet);
		//4.关闭
		socket.close();
	}

}
//====================================
package com.hanker2;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
//先客户端,再启动服务器发送
public class UDPClient {

	public static void main(String[] args) throws Exception {
		System.out.println("客户端准备接收......");
		//1.创建socket客户端
		DatagramSocket socket =new DatagramSocket(8888);
		//2. 创建数据包,指定缓冲区
		byte[] buf = new byte[1024];
		DatagramPacket p = new DatagramPacket(buf , buf.length);		
		//3.接收数据包
		socket.receive(p);
		//接收的真实数据的长度
		int len = p.getLength();
		System.out.println("接收的数据长度:"+len);
		//获取接收的数据
		byte[] data = p.getData();
		System.out.println("data.length=="+data.length);
		System.out.println("接收到数据:" + new String(data,0,len));
		//5.关闭socket
		socket.close();
	}
}

在这里插入图片描述

双向通信

package net2;

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

public class UDPServer2 {

	public static void main(String[] args) throws Exception {
		//1.创建DatagrammSocket对象 发送和接收 (对讲机)
		DatagramSocket server = new DatagramSocket();
		//2.创建发送的数据报
		/*
		 1.发送内容的字节数组
		 2.发送内容的长度
		 3.目标主机
		 3.目标主机的端口号 
		*/
		String msg = "前面交警拦截红色的法拉利.";
		DatagramPacket packet =
			new DatagramPacket(
					msg.getBytes(), 
					msg.getBytes().length, 
					InetAddress.getByName("localhost"), 
					9001);
		
		//3.发送
		server.send(packet);
		
		//==========接收============
		//1.创建一个信封
		//重新创建一个Socket负责接收
		DatagramSocket server2 = new DatagramSocket(9002);
		byte[] buf = new byte[1024];
		DatagramPacket p = new DatagramPacket(buf, buf.length);
		server2.receive(p);
		String returnValue=new String(p.getData(),0,p.getLength());
		System.out.println("返回信息:"+returnValue);
		server.close();
		server2.close();
	}

}
//================================
package net2;

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

public class UDPClient2 {

	public static void main(String[] args) throws Exception {
		//1.创建Socket对象
		DatagramSocket client = new DatagramSocket(9001);
		byte[] buf=new byte[1024];
		DatagramPacket p = new DatagramPacket(buf, buf.length);
		//2.客户端接收
		client.receive(p);
		//3.用接收到的数据构建一个字符串
		//p.getLength() 是客户端真正接收到数据的长度
		String msg = new String(p.getData(),0,p.getLength());
		System.out.println("收到信息:"+msg);
		//=========发送==========
		String word="已经拦截到法拉利,酒驾..";
		DatagramPacket packet = new DatagramPacket(
				word.getBytes(), 
				word.getBytes().length, 
				InetAddress.getByName("localhost"),
				9002);
		client.send(packet);
		
		client.close();
	}

}

下载工具

package com.hanker2;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class DownloadUtil {

	public static void main(String[] args) throws Exception {
		String url = "https://c-ssl.duitang.com/uploads/item/201807/14/20180714211943_vlvpq.thumb.700_0.jpg";
		//表示统一资源定位符,网络上的唯一资源
		URL urlAdd = new URL(url);
		//基于该资源打开一个连接
		URLConnection conn = urlAdd.openConnection();
		//获取输入流
		InputStream inputStream = conn.getInputStream();
		//创建目标文件
		File file = new File("d:\\girl.jpg");		
		//根据该图片的有效字节数创建数组
		byte [] buf = new byte[1024];
		FileOutputStream fos = new FileOutputStream(file);
		int len = 0;  
		while( (len=inputStream.read(buf)) != -1) {
			fos.write(buf,0,len);
		}
		fos.close();
		inputStream.close();
	}

}

获取URL相关信息

package tcp;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

public class URLDemo {
	public static void main(String[] args) throws IOException {
		String str_url = "http://192.168.1.100:8080/myweb/1.html?name=admin";
		URL url = new URL(str_url);
		System.out.println("getProtocol:" + url.getProtocol());
		System.out.println("getHost:" + url.getHost());
		System.out.println("getPort:" + url.getPort());
		System.out.println("getFile:" + url.getFile());
		System.out.println("getPath:" + url.getPath());
		System.out.println("getQuery:" + url.getQuery());
		//InputStream in = url.openStream();
		//获取url对象的Url连接器对象。将连接封装成了对象:java中内置的可以解析的具体协议的对象+socket.
				URLConnection conn = url.openConnection();
		//String value = conn.getHeaderField("Content-Type");
		//System.out.println(value);
		//System.out.println(conn);
		//sun.net.www.protocol.http.HttpURLConnection:http://192.168.1.100:8080/myweb/1.html
		InputStream in = conn.getInputStream();
		byte[] buf = new byte[1024];
		int len = in.read(buf);

		String text = new String(buf, 0, len);
		System.out.println(text);
		in.close();
	}
}

编码工具类

URLDecoder HTML表单解码的实用类。  
URLEncoder HTML表单编码的实用类。  
package com.hanker2;

import java.net.URLDecoder;
import java.net.URLEncoder;

public class EncodeUtil {

	public static void main(String[] args) throws Exception {
		String s = "https://www.baidu.com/s?wd=%E8%BF%AA%E4%B8%BD%E7%83%AD%E5%B7%B4";
		String decode = URLDecoder.decode(s, "utf8");
		System.out.println("解码之后:"+decode);
		String str = "张书峰";
		String encode = URLEncoder.encode(str, "utf8");
		System.out.println("编码之后:"+encode);
	}
}

手写服务器

package com.hanker2;

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

public class MyTomcat {

	public static void main(String[] args) throws Exception {
		System.out.println("服务器启动成功过.......");
		//1.创建ServerSocket
		ServerSocket serverSocket = new ServerSocket(8080);
		//2.等待连接
		Socket socket = serverSocket.accept();
		//3.获取连接的信息
		InputStream inputStream = socket.getInputStream();
		byte[] buf = new byte[1024];
		int len = inputStream.read(buf);
		System.out.println("客户端信息:"+new String(buf,0,len));
		//4.向客户端发送信息
		OutputStream outputStream = socket.getOutputStream();
		PrintWriter out = new PrintWriter(outputStream, true);
		out.println("<h1 style=\"color:red\">欢迎访问我的网站</h1>");
		out.close();
		socket.close();
		serverSocket.close();
	}

}

在这里插入图片描述
在这里插入图片描述

模拟浏览器

package tcp;

import java.io.InputStream;
import java.io.PrintWriter;
import java.net.Socket;

public class MyBrowser {
	public static void main(String[] args) throws Exception {
		Socket s = new Socket("localhost", 8080);
		// 模拟浏览器,给tomcat服务端发送符合http协议的请求消息。
		PrintWriter out = new PrintWriter(s.getOutputStream(), true);
		out.println("GET /myweb/1.html HTTP/1.1");
		out.println("Accept: */*");
		out.println("Host: 192.168.1.100:8080");
		out.println("Connection: close");
		out.println();
		out.println();
		InputStream in = s.getInputStream();
		byte[] buf = new byte[1024];
		int len = in.read(buf);
		String str = new String(buf, 0, len);
		System.out.println(str);

		s.close();
		// http://192.168.1.100:8080/myweb/1.html
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值