网络编程三要素
(1)IP:设备在网络中的位置
(2)端口号:应用程序在设备中的地址(范围: 0 ~ 65535 之间。其中 0 - 1023 是系统端口号。 1024 以上的端口号才能被我们使用。)
(3)协议:UDP和TCP
IP指令
ping IP地址(查看该地址网络是否连通)
ipconfig (查看自己的IP地址)
InetAddress类
(1)常用方法
方法 | 备注 |
---|---|
static InetAddress getByName(String host) | 通过主机名称或者IP地址, 获取到 InetAddress 对象。(既可以传递IP地址,也可以传递主机名) |
String getHostName() | 获取此IP地址的主机名 |
String getHostAddress() | 返回文本显示中的IP地址字符串 |
协议
(1)UDP 协议
a) 传输速度:快
b) 传输数据量:小 最大64KB
c) 安全性:低
(2)TCP 协议
a) 传输速度:慢
b) 传输数据量:大 无上限
c) 安全性:高
UDP协议
(1)UDP的三种通信方式
a) 单播: 一个发送端 和 一个接收端
b) 组播: 一个发送端 和 一组(多个)接收端
c) 广播: 一个发送端 和 一群(所有)接收端
(2)单播实现案例
//发送端
public class SendDemo {
public static void main(String[] args) throws IOException {
System.out.println("发送端");
// (1). 创建对象
DatagramSocket ds = new DatagramSocket();
// (2). 打包数据
String message = "Hello,你好呀.";
byte[] data = message.getBytes();
int length = data.length;
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 10086; //说明:IP和端口指的是 接收端的IP和接收端的端口
// --------
DatagramPacket dp = new DatagramPacket(data,length,address,port);
// (3). 发送数据
ds.send(dp);
// (4). 释放资源
ds.close();
}
}
//接收端【先运行接收端】
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
System.out.println("接收端");
// (1). 创建对象 ---> 需要传递参数:端口号
DatagramSocket ds = new DatagramSocket(10086);
// (2). 准备包裹
byte[] data = new byte[1024];
int len = data.length;
DatagramPacket dp = new DatagramPacket(data,len);
// (3). 接收数据
ds.receive(dp);
// (4). 解析数据
String message = new String(data,0,dp.getLength());
System.out.println(message);
// (5). 释放资源
ds.close();
}
}
(3)组播
a) 发送端
需要修改发送端的 IP地址: 224.0.1.0到后面的IP
b) 接收端
aa) 创建对象 MulticastSocket ms = new MulticastSocket(10086);
bb) 需要添加组播地址 ms.joinGroup(InetAddress.getByName(“224.0.1.1”));
cc) 接收组播数据. ms.receive(dp);
dd) 释放资源. ms.close();
c) 案例
//发送端: 想一想发快递
public class SendDemo {
public static void main(String[] args) throws Exception{
// (1). 创建对象 找到快递点
DatagramSocket ds = new DatagramSocket();
// (2). 打包快递 将要发送的内容进行打包处理
byte[] data = "Hello,几个老哥,不要在sleep".getBytes();
int length = data.length;
//IP地址是 接收端的IP地址
InetAddress address = InetAddress.getByName("224.0.1.1");
//端口号是 接收端的端口号
int port = 10086;
DatagramPacket dp = new DatagramPacket(data,length,address,port);
// (3). 发送快递
ds.send(dp);
// (4). 结单
ds.close();
}
}
//接收端:想一想接收快递[先运行接收端]
public class ReceiveDemo {
public static void main(String[] args) throws Exception {
// (1). 创建对象 找到快递点
MulticastSocket ms = new MulticastSocket(10086);
//添加到组播地址
ms.joinGroup(InetAddress.getByName("224.0.1.1"));
// (2). 准备一个新的包裹 箱子
byte[] data = new byte[1024];
DatagramPacket dp = new DatagramPacket(data,data.length);
// (3). 接收快递
ms.receive(dp);
// (4). 打开快递 解析数据
String message = new String(data,0,dp.getLength());
String address = dp.getAddress().getHostAddress();
System.out.println(address+"说:"+message);
// (5). 结单
ms.close();
}
}
(4)广播
a) 需要修改发送端的 IP 地址: 255.255.255.255
b) 案例
//发送端: 想一想发快递
public class SendDemo {
public static void main(String[] args) throws Exception{
// (1). 创建对象 找到快递点
DatagramSocket ds = new DatagramSocket();
// (2). 打包快递 将要发送的内容进行打包处理
byte[] data = "Hello,几个老哥,不要在sleep".getBytes();
int length = data.length;
//IP地址是 接收端的IP地址
InetAddress address = InetAddress.getByName("255.255.255.255");
//端口号是 接收端的端口号
int port = 10086;
DatagramPacket dp = new DatagramPacket(data,length,address,port);
// (3). 发送快递
ds.send(dp);
// (4). 结单
ds.close();
}
}
//接收端:想一想接收快递[先运行接收端]
public class ReceiveDemo {
public static void main(String[] args) throws Exception {
// (1). 创建对象 找到快递点
DatagramSocket ds = new DatagramSocket(10086);
// (2). 准备一个新的包裹 箱子
byte[] data = new byte[1024];
DatagramPacket dp = new DatagramPacket(data,data.length);
// (3). 接收快递
ds.receive(dp);
// (4). 打开快递 解析数据
String message = new String(data,0,dp.getLength());
String address = dp.getAddress().getHostAddress();
System.out.println(address+"说:"+message);
// (5). 结单
ds.close();
}
}
TCP协议
(1)案例演示原理
//词霸客户端
public class CiBaClient {
public static void main(String[] args) throws IOException {
String word = "hello";
// (1). 准备发送数据给服务端 --》输出 IP和端口 都是服务端的
Socket clientSocket = new Socket("127.0.0.1",6666);
OutputStream os = clientSocket.getOutputStream();
os.write(word.getBytes());
// (2). 准备接收到服务端回复的数据--》输入
InputStream is = clientSocket.getInputStream();
byte[] array = new byte[1024];
int len = is.read(array);
String message = new String(array,0,len);
System.out.println(message);
clientSocket.close(); //释放资源
}
}
//词霸 服务端 【先运行服务端】
public class CiBaServer {
public static void main(String[] args) throws IOException {
System.out.println("你好,黑马词霸服务器开启了...");
// --------
ServerSocket serverSocket = new ServerSocket(6666);
Socket clientSocket = serverSocket.accept(); //客户端的Socket
// (1). 接收来自于客户端的数据 --》输入流
InputStream is = clientSocket.getInputStream();
byte[] array = new byte[1024];
int len = is.read(array);
String word = new String(array,0,len);
// (2). 单词的查找
HashMap<String,String> map = new HashMap<>();
map.put("hello","你好呀");
map.put("world","世界");
map.put("java","牛逼的语言");
String value = map.get(word);
value = (value == null)?"请充值VIP":value;
// (3). 返回结果--》输出流
OutputStream os = clientSocket.getOutputStream();
os.write(value.getBytes());
clientSocket.close(); //释放资源
}
}
案例原理图
(2)词霸案例(单线程和多线程)
a) 单线程
//词霸 客户端 引入外部词库
public class CiBaClientDemo {
public static void main(String[] args) throws Exception{
while(true){
Scanner sc = new Scanner(System.in);
System.out.println("请输入需要翻译的单词:(886则退出)");
String word = sc.nextLine();
//如果是 886 则退出循环
if ("886".equals(word)){
break;
}
// (1). 创建 客户端 clientSocket 的对象
Socket clientSocket = new Socket("127.0.0.1",10086);
// (2). 需要发送数据给 服务端
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
bw.write(word);
bw.newLine(); //因为 br 需要读取到换行符才会结束,需要给他一个换行符
bw.flush(); //因为 bw 写数据是写入到缓冲区,需要通过刷新它才能够写过去!
// (3). 接收来自于服务端 翻译的数据
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String message = br.readLine();
System.out.println(message);
// (4). 释放资源
clientSocket.close();
}
}
}
//词霸 服务端 引入外部词库
//服务端: 将Map集合转换成为 Properties 写法
public class CiBaServerDemo {
public static void main(String[] args) throws IOException {
String path = "JavaSEDay17\\dir\\ciba.properties";
Properties pp = new Properties();
//看你的编码方式是什么类型? 如果编码方式是 UTF-8 则不需要转换,如果是 GBK 则建议采用转换流,解决中文乱码
pp.load(new InputStreamReader(new FileInputStream(path),"GBK"));
// --------
// (1). 创建服务器的 ServerSocket 的对象
ServerSocket serverSocket = new ServerSocket(10086);
while(true){
// (2). 获取到 客户端的 clientSocket 的对象
Socket clientSocket = serverSocket.accept();
// (3). 接收来自于客户端的数据
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String word = br.readLine(); //因为只是写了一行数据,读数据只需要读取一行
// (4). 处理数据逻辑(翻译 java --> 中文)
String message = "不好意思啊,你还不是SSVIP,请充值";
//通过 Map 集合,查找单词数据
String value = pp.getProperty(word);
//如果值为 null,不好意思啊... 如果不为null 得到结果就是 value值
message = (value == null) ? message : value;
// (5). 准备写回结果数据 给客户端
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
bw.write(message);
bw.newLine();
bw.flush();
// (6). 释放资源
clientSocket.close();
}
}
}
b) 多线程
// 线程类,用于处理多线程
public class MyThread implements Runnable {
private Socket clientSocket;
private HashMap<String, String> map;
public MyThread(Socket clientSocket, HashMap<String, String> map) {
this.clientSocket = clientSocket;
this.map = map;
}
@Override
public void run() {
try {
// 获取客户端发送的数据
InputStream is = clientSocket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String word = br.readLine();
// 获取翻译
String value = map.get(word);
value = value == null ? "请充值会员" : value;
// 将数据返回给客户端
// 获取输出流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
bw.write(value);
bw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (clientSocket != null) {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
// 客户端
public class Client {
public static void main(String[] args) throws IOException {
while (true) {
Scanner sc = new Scanner(System.in);
// 创建客户端socket对象
Socket client = new Socket("127.0.0.1",10086);
// 准备数据
System.out.print("输入单词:");
String word = sc.nextLine();
// 获取输出流传输数据
OutputStream clientOutputStream = client.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientOutputStream));
bw.write(word);
bw.newLine();
bw.flush();
// 获取服务器回传的数据
BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));
String s = br.readLine();
System.out.println("翻译:"+s);
if ("886".equals(word)){
break;
}
client.close();
}
}
}
// 服务器端
public class Server {
private static HashMap<String, String> map = new HashMap<>();
// 加载配置文件的字典数据
static {
BufferedReader br = null;
try {
// 加载字典文件
br = new BufferedReader(new FileReader("day15/homeworkdir/dictionary.txt"));
String line;
while ((line = br.readLine()) != null) {
// 将读取的内容转换为map
String[] split = line.split("=");
map.put(split[0], split[1]);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws IOException {
System.out.println("词霸已上线.......");
ServerSocket ss = new ServerSocket(10086);
ThreadPoolExecutor pool = new ThreadPoolExecutor(
3,
5,
60,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
while (true) {
Socket clientSocket = ss.accept();
MyThread myThread = new MyThread(clientSocket, map);
pool.submit(myThread);
clientSocket.close();
}
}
}
(3)文件上传(单线程和多线程)
a) 单线程
//文件上传的客户端:
public class UpLoadClientDemo {
public static void main(String[] args) throws Exception {
String path = "JavaSEDay17\\dir\\meizi.png";
Socket clientSocket = new Socket("127.0.0.1", 10086);
// --------
// (1). 本地流 输入到程序当中, 网络流 输出到 服务器
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
BufferedOutputStream bos = new BufferedOutputStream(clientSocket.getOutputStream());
byte[] data = new byte[1024];
int len;
while ((len = bis.read(data)) != -1) {
bos.write(data, 0, len);
bos.flush();
}
//===============
//需要写一个结束标记
clientSocket.shutdownOutput();
//===============
// (4). 获取到服务器的数据
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String message = br.readLine();
System.out.println(message);
clientSocket.close();
}
}
//文件上传的服务端:
public class UpLoadServerDemo {
public static void main(String[] args) throws IOException {
System.out.println("服务器启动了...");
String path = "JavaSEDay17\\dir\\mz001.png";
ServerSocket serverSocket = new ServerSocket(10086);
Socket clientSocket = serverSocket.accept();
// (2). 网络流 接收来自于客户端的数据,写出到本地
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(path));
BufferedInputStream bis = new BufferedInputStream(clientSocket.getInputStream());
byte[] data = new byte[1024];
int len;
while ((len = bis.read(data)) != -1) {
bos.write(data, 0, len);
bos.flush();
}
// (3). 写回结果给客户端
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
bw.write("文件上传成功!");
bw.newLine();
bw.flush();
clientSocket.close();
}
}
b) 多线程
//文件上传的客户端:
public class UpLoadClientDemo {
public static void main(String[] args) throws Exception {
String path = "JavaSEDay17\\dir\\meizi.png";
Socket clientSocket = new Socket("127.0.0.1", 10086);
// --------
// (1). 本地流 输入到程序当中, 网络流 输出到 服务器
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(path));
BufferedOutputStream bos = new BufferedOutputStream(clientSocket.getOutputStream());
byte[] data = new byte[1024];
int len;
while ((len = bis.read(data)) != -1) {
bos.write(data, 0, len);
bos.flush();
}
//===============
//需要写一个结束标记
clientSocket.shutdownOutput();
//===============
// (4). 获取到服务器的数据
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String message = br.readLine();
System.out.println(message);
clientSocket.close();
}
}
//文件上传的服务端:
//1. 文件的名称需要随机出现。UUID.randomUUID().toString();
//2. 服务器需要处于长期开启状态。 添加死循环操作
// ------> 针对于第二步而言:
// ----------> A. 在 accept() 方法的下面,进行抽取
// ----------> B. 添加死循环操作 while(true){ ... }
public class UpLoadServerDemo {
public static void main(String[] args) throws IOException {
System.out.println("服务器启动了...");
ServerSocket serverSocket = new ServerSocket(10086);
while (true) {
Socket clientSocket = serverSocket.accept();
upload(clientSocket);
}
}
//抽取成为一个方法
public static void upload(Socket clientSocket) throws IOException {
//随机生成一个字符串序列.作为文件的名称
String name = UUID.randomUUID().toString();
String path = "JavaSEDay17\\dir\\" + name + ".png";
// (2). 网络流 接收来自于客户端的数据,写出到本地
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(path));
BufferedInputStream bis = new BufferedInputStream(clientSocket.getInputStream());
byte[] data = new byte[1024];
int len;
while ((len = bis.read(data)) != -1) {
bos.write(data, 0, len);
bos.flush();
}
// (3). 写回结果给客户端
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
bw.write("文件上传成功!");
bw.newLine();
bw.flush();
clientSocket.close();
}
}