课程回顾
多线程,
创建线程的三种方式:
①继承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
}
}