网络通信,UDP通信,TCP通信
网络通信3要素
要素1:IP地址
IP地址操作类: InetAddress
package com.heima.test;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressDemo {
public static void main(String[] args) throws Exception {
//获取本机地址对象
InetAddress ip1 = InetAddress.getLocalHost();
//本机局域网ip地址
System.out.println(ip1);
//主机名
System.out.println(ip1.getHostName());
//局域网ip地址
System.out.println(ip1.getHostAddress());
//获取域名ip对象
InetAddress ip2 = InetAddress.getByName("www.baidu.com");
System.out.println(ip2.getHostName());
System.out.println(ip2.getHostAddress());
//获取公网ip对象
InetAddress ip3 = InetAddress.getByName("119.63.197.151");
System.out.println(ip3.getHostName());
System.out.println(ip3.getHostAddress());
//判断是否能通:ping 5s之内测试是否可通
System.out.println(ip3.isReachable(5000));
}
}
要素2:端口号
要素3:协议
- 连接和通信数据的规则被称为网络通信协议
UDP通信
基础知识
package com.heima.test.TCP;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
//接收端
public class ServerDemo {
public static void main(String[] args) throws Exception {
System.out.println("============服务端先启动=============");
//创建接收端对象,注册端口号要与发送端一致
DatagramSocket socket = new DatagramSocket(8888);
//创建数据包对象接收数据
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
//等待接受数据
socket.receive(packet);
//取出数据
//读取多少倒出多少
int len = packet.getLength();
String s = new String(buffer, 0, len);
System.out.println("收到了 :" + s);
//获取发送端的ip和端口
String ip = packet.getSocketAddress().toString();
System.out.println("对方的地址 :" + ip);
int port = packet.getPort();
System.out.println("对方端口 : " + port);
socket.close();
}
}
package com.heima.test.TCP;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
//发送端
public class ClientDemo {
public static void main(String[] args) throws Exception {
System.out.println("=================客户端后启动===================");
//创建发送端对象,自带默认端口
DatagramSocket socket = new DatagramSocket(6666);
//创建一个数据包对象封装数据
// public DatagramPacket(byte buf[], int length,
// InetAddress address, int port) {
// this(buf, 0, length, address, port);
//buf[] 封装要发送的数据
//length 此字节数组的长度
//服务端ip地址
//服务端端口
byte[] buffer = "我是一个中国人".getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLocalHost(), 8888);
//发送数据
socket.send(packet);
//关闭管道
socket.close();
}
}
多发多收
- 如果需要同时开启多个客户端,idea需要设置一下
package com.heima.test.TCP;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
//发送端 多发多收
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("=================客户端1后启动===================");
//创建发送端对象,自带默认端口
DatagramSocket socket = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
//按行收发消息
System.out.println("请你说 : ");
String msg = sc.nextLine();
if ("exit".equals(msg)){
System.out.println("离线成功");
socket.close();
break;
}
//创建一个数据包对象封装数据
byte[] buffer = msg.getBytes();
//DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLocalHost(), 8888);
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("192.168.0.109"), 9999);
//发送数据
socket.send(packet);
}
}
}
package com.heima.test.TCP;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
//接收端
public class ServerDemo1 {
public static void main(String[] args) throws Exception {
System.out.println("============服务端1先启动=============");
//创建接收端对象,注册端口号要与发送端一致
DatagramSocket socket = new DatagramSocket(9999);
//创建数据包对象接收数据
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
//等待接受数据
socket.receive(packet);
//取出数据
//读取多少倒出多少
int len = packet.getLength();
String s = new String(buffer, 0, len);
System.out.println("收到了来自 :" + packet.getAddress() + ",对方端口是" + packet.getPort() + "的消息 : " + s);
}
}
}
广播,组播
- 广播
package com.hyway.delivergoods.test;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class UDPClientBroadcast {
public static void main(String[] args) throws Exception {
System.out.println("=========windows笔记本客户端启动=========");
DatagramSocket socket = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入消息 : ");
String msg = sc.nextLine();
if ("exit".equals(msg)) {
System.out.println("离线成功");
socket.close();
return;
}
byte[] buffer = msg.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("255.255.255.255"), 9999);
socket.send(packet);
}
}
}
package com.hyway.delivergoods.test;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPServerBroadcast {
public static void main(String[] args) throws Exception {
System.out.println("=============windows笔记本服务端启动==============");
DatagramSocket socket = new DatagramSocket(9999);
byte[] buffer = new byte[1024 * 8];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
socket.receive(packet);
int len = packet.getLength();
String s = new String(buffer, 0, len);
System.out.println("收到了来自mac :" + packet.getAddress() + ",对方端口是 " + packet.getPort() + "的消息 :" + s);
}
}
}
- 组播
package com.hyway.delivergoods.test;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class UDPClientGroupcast {
public static void main(String[] args) throws Exception {
System.out.println("=========windows笔记本客户端启动=========");
DatagramSocket socket = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入消息 : ");
String msg = sc.nextLine();
if ("exit".equals(msg)) {
System.out.println("离线成功");
socket.close();
return;
}
byte[] buffer = msg.getBytes();
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("224.0.1.1"), 9999);
socket.send(packet);
}
}
}
package com.hyway.delivergoods.test;
import java.net.*;
public class UDPServerGroupcast {
public static void main(String[] args) throws Exception {
System.out.println("=============windows笔记本服务端启动==============");
MulticastSocket socket = new MulticastSocket(9999);
//当前接收端加入一个组播组中去,绑定对应的组播消息的组播IP
//此方法可用,可是过时了
//socket.joinGroup(InetAddress.getByName("224.0.1.1"));
//第二个参数是当前主机所在的网段
socket.joinGroup(new InetSocketAddress(InetAddress.getByName("224.0.1.1"),9999),
NetworkInterface.getByInetAddress(InetAddress.getLocalHost()));
byte[] buffer = new byte[1024 * 8];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
socket.receive(packet);
int len = packet.getLength();
String s = new String(buffer, 0, len);
System.out.println("收到了来自mac :" + packet.getAddress() + ",对方端口是 " + packet.getPort() + "的消息 :" + s);
}
}
}
TCP通信
基础知识-Socket套接字
package com.heima.test.TCP1;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
//Socket网络编程的客户端,实现一发一收
public class SocketClient {
public static void main(String[] args) {
try {
System.out.println("==============客户端启动成功==============");
//创建Socket通信管道请求服务端的连接
//服务端的IP地址,服务端的端口
Socket socket = new Socket("127.0.0.1", 7777);
//从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
//发送消息
//因为服务端只能接收一行消息,会导致服务器端挂掉,Connection reset
//ps.print("我是TCP客户端,我已经与你对接,并发出邀请:约吗?");
ps.println("我是TCP客户端,我已经与你对接,并发出邀请:约吗?");
ps.flush();
//不要关闭资源,会导致有些信息发送丢失,除非用户点离线才关闭
//socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.heima.test.TCP1;
//Socket网络编程的服务端,实现接受消息
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketServer {
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket serverSocket = new ServerSocket(7777);
//必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
//进入等待状态
Socket socket = serverSocket.accept();
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接收
//BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8"));
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息
String msg;
//while ((msg = br.readLine()) != null) {
//while接收多行消息,服务器还是会死掉
if ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + "远程地址说了 : " + msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
多发多收消息
package com.heima.test.TCP1;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
//Socket网络编程的客户端,实现多发多收
public class MultiSocketClient {
public static void main(String[] args) {
try {
System.out.println("==============客户端启动成功==============");
//创建Socket通信管道请求服务端的连接
//服务端的IP地址,服务端的端口
Socket socket = new Socket("127.0.0.1", 7777);
//从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说 : ");
String msg = sc.nextLine();
//发送消息
ps.println(msg);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.heima.test.TCP1;
//Socket网络编程的服务端,实现接受消息
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class MultiSocketServer {
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket serverSocket = new ServerSocket(7777);
//必须调用accept方法:等待接收客户端的Socket连接请求,建立Socket通信管道
//进入等待状态
Socket socket = serverSocket.accept();
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接收
//BufferedReader br = new BufferedReader(new InputStreamReader(is,"UTF-8"));
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + "远程地址说了 : " + msg);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
同时接受多个客户端消息(重点)
package com.heima.test.TCP1;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
//Socket网络编程的客户端,实现服务端可以同时处理多个客户端消息
public class ThreadSocketClient {
public static void main(String[] args) {
try {
System.out.println("==============客户端启动成功==============");
//创建Socket通信管道请求服务端的连接
//服务端的IP地址,服务端的端口
Socket socket = new Socket("127.0.0.1", 7777);
//从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说 : ");
String msg = sc.nextLine();
//发送消息
ps.println(msg);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.heima.test.TCP1;
//Socket网络编程的服务端,实现服务端可以同时处理多个客户端消息
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class ThreadSocketServer {
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket serverSocket = new ServerSocket(7777);
//定义一个死循环由主线程负责不断地接收客户端的Socket管道连接
while (true) {
//每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress()+" 上线了!");
//创建独立线程处理socket
new ServerReaderThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.heima.test.TCP1;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接收
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + " 远程地址说了 : " + msg);
}
} catch (Exception e) {
// e.printStackTrace();
System.out.println(socket.getRemoteSocketAddress() + " 离开了!!!");
}
}
}
使用线程池优化
package com.heima.test.TCP1;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
//Socket网络编程的客户端,实现服务端可以同时处理多个客户端消息
//使用线程池优化代码
//客户端不用动
public class ThreadSocketClient {
public static void main(String[] args) {
try {
System.out.println("==============客户端启动成功==============");
//创建Socket通信管道请求服务端的连接
//服务端的IP地址,服务端的端口
Socket socket = new Socket("127.0.0.1", 6666);
//从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说 : ");
String msg = sc.nextLine();
//发送消息
ps.println(msg);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.heima.test.TCP1;
//Socket网络编程的服务端,实现服务端可以同时处理多个客户端消息
//使用线程池优化代码
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
public class ThreadSocketServer {
//使用静态变量记住一个线程池对象,用于处理任务
//上限是5线程或7任务
private static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(2),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket serverSocket = new ServerSocket(6666);
//定义一个死循环由主线程负责不断地接收客户端的Socket管道连接
while (true) {
//每接收到一个客户端的Socket管道,交给一个独立的子线程负责读取消息
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress() + " 上线了!");
//创建任务对象交给线程池处理
//任务对象负责读取消息
Runnable target = new ServerReaderRunnable(socket);
pool.execute(target);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
package com.heima.test.TCP1;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
//任务队列
public class ServerReaderRunnable implements Runnable {
private Socket socket;
public ServerReaderRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接收
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + " 远程地址说了 : " + msg);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + " 离开了!!!");
}
}
}
实战案例 - 即时通信
package com.heima.test.TCP2;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
//客户端既能收消息,也可以发送消息
public class ClientMSG {
public static void main(String[] args) {
try {
System.out.println("==============客户端启动成功==============");
//创建Socket通信管道请求服务端的连接
//服务端的IP地址,服务端的端口
Socket socket = new Socket("127.0.0.1", 6666);
//创建一个独立的线程专门负责这个客户端的读消息(服务端随时可能转发消息过来!)
new ClientReaderThread(socket).start();
//从socket通信管道中得到一个字节输出流,负责发送数据
OutputStream os = socket.getOutputStream();
//把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请说 : ");
String msg = sc.nextLine();
//发送消息
ps.println(msg);
ps.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
//客户端读线程
class ClientReaderThread extends Thread {
private Socket socket;
public ClientReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接收
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(" 收到了消息 : " + msg);
}
} catch (Exception e) {
System.out.println("服务端把你踢出去了。。。");
}
}
}
package com.heima.test.TCP2;
import com.heima.test.TCP1.ServerReaderRunnable;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class ServerMSG {
//定义一个静态的List集合存储当前全部在线socket管道
public static List<Socket> allOnlineSocket = new ArrayList<>();
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket serverSocket = new ServerSocket(6666);
//循环接收客户端socket管道请求
while (true) {
//开始接收客户端的socket管道连接请求
//注意:在这里等待客户端的socket管道连接
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress() + " 上线了!");
allOnlineSocket.add(socket);//上线完成
//创建一个独立的线程来单独处理这个socket管道
new ServerReaderThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//从socket通信管道得到一个字节输入流
InputStream is = socket.getInputStream();
//把字节输入流包装成缓冲字符输入流进行消息的接收
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + " 发来了 : " + msg);
//把这个消息进行端口转发给全部客户端socket管道
sendMsgToAll(msg);
}
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + " 离开了!!!");
ServerMSG.allOnlineSocket.remove(socket);
}
}
private void sendMsgToAll(String msg) throws Exception {
for (Socket socket : ServerMSG.allOnlineSocket) {
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println(msg);
ps.flush();
}
}
}
- 没有排除自己,自己也能收到消息
实战案例 - 模拟BS系统
package com.heima.test.TCP3;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class BSserver {
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket ss = new ServerSocket(8080);
//创建一个循环接收多个客户端请求
while (true) {
Socket socket = ss.accept();
//交给一个独立线程处理
new ServerReaderThread(socket).start();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//浏览器已经与本线程建立了socket管道
//响应消息给浏览器显示
PrintStream ps = new PrintStream(socket.getOutputStream());
//必须响应HTTP协议格式数据,否则浏览器·不认识消息
ps.println("HTTP/1.1 200 OK");
ps.println("Content-Type:text/html;charset=UTF-8");
ps.println();//必须发送一个空行
//才可以响应数据回去给浏览器
ps.println("<span style='color:red;font-size:90px'>我是响应信息</span>");
ps.close();
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + " 离开了!!!");
}
}
}
- 使用线程池实现
package com.heima.test.TCP3;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
public class BSserver {
//使用静态变量记住一个线程池对象,用于处理任务
//上限是5线程或7任务
private static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6,
TimeUnit.SECONDS, new ArrayBlockingQueue<>(2),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
try {
System.out.println("==============服务端启动成功==============");
//注册端口
ServerSocket ss = new ServerSocket(8080);
//创建一个循环接收多个客户端请求
while (true) {
Socket socket = ss.accept();
//交给一个独立线程处理
pool.execute(new ServerReaderRunnable(socket));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ServerReaderRunnable implements Runnable {
private Socket socket;
public ServerReaderRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//浏览器已经与本线程建立了socket管道
//响应消息给浏览器显示
PrintStream ps = new PrintStream(socket.getOutputStream());
//必须响应HTTP协议格式数据,否则浏览器·不认识消息
ps.println("HTTP/1.1 200 OK");
ps.println("Content-Type:text/html;charset=UTF-8");
ps.println();//必须发送一个空行
//才可以响应数据回去给浏览器
ps.println("<span style='color:red;font-size:90px'>我是响应信息2</span>");
ps.close();
} catch (Exception e) {
System.out.println(socket.getRemoteSocketAddress() + " 离开了!!!");
}
}
}