目录
一。网络的相关概念
1.网络的分类
根据网络覆盖的范围来区分,中国大陆地区就是一个特别大的局域网
2.ip地址
由于连入联网的设备扩展了(万物互联的概念),由单纯计算机主机可以联网,扩展到了手机,手表,电视等都可以。ipv4的地址不够用,所以扩展出了ipv6。 八个二进制位为一个字节,ipv4占用四个字节,ipv6站十六个字节。
服务器的ip地址是固定的,一般电脑上网的ip地址是不固定的 。
3.域名和端口号
因为ip地址不好记忆,所以就用域名代替了ip地址,ip与域名的转换是遵守dns规则的。
如果把你的电脑想成一个客栈,他会有很多的门,不同的门对应不同的服务,别的主机传送来的消息,都会从你的门来给你传入。客栈的门就相当于电脑的端口。
访问网站,是以端口+服务的形式来实现网站的访问的。
端口号一共占有两个字节。
一个端口只能绑定一个服务。端口只与网络服务有关。
4.网络通信协议
先拿人与人之间的交流做比较,语言可以说是一种协议(规范)不遵守,对方就听不懂了。网络之间的信息传输也遵循着一套协议。消息经过固定的格式打包,就像是语言交流当中的语法。(简单解释)
数据封装的过程
像是快递,要有打包的过程,只有打包过后的程序,才能发送。这是打包,用户解析是反过来的。
数据的解析形式就是协议,协议,把信息准确无误的发送给对方。计算机之间相互沟通的行为规范。
网络通信协议模型
主要是tcp模型,osi模型太细,区分太细没有意义。
tcp和ip协议是最基础的信息协议,链路是用来增加帧头和帧尾的。如果我们设置 一个信息包的发送,识别规则,那他是建立在tcp,ip协议的基础之上的。
5.tcp和udp协议
传输层两个协议的区别。
tcp:可靠,量大,效率低。
你人比喻模拟
两人打电话,打通了之后,要先确认双方到底能不能互相正确的接收到信息。A说你好之后,B回你好之后,在说明要说事情了,才能确保通话正常。
一班传送数据文件音频。
udp:不可靠,量小,但是速度快。
直接将信息发送给你,不管你接收不接收,发送给你之后就完事了。
6.重要的方法
InetAdress当中的一些方法
package com.api; import java.net.InetAddress; import java.net.UnknownHostException; public class API_ { public static void main(String[] args) throws UnknownHostException { // 获得本机的InetAddress对象 InetAddress localHost = InetAddress.getLocalHost(); System.out.println(localHost); // 根据指定的主机名获得InetAddress对象 InetAddress byName = InetAddress.getByName("LAPTOP-D83EFCRR"); System.out.println(byName); // 根据域名返回对应的ip InetAddress byName1 = InetAddress.getByName("www.baidu.com"); System.out.println(byName1); // 通过getHostAddress对象使他获得对应的地址ipv4地址 String hostAddress = byName1.getHostAddress(); System.out.println(hostAddress); // 获取对应的域名 String hostName = byName1.getHostName(); System.out.println(hostName); } }
运行结果
LAPTOP-D83EFCRR/192.168.0.103
LAPTOP-D83EFCRR/192.168.0.103
www.baidu.com/220.181.38.150
220.181.38.150
www.baidu.com
二.Socket网络编程
数据在两个socket当中通过io流进行传播
一段服务,一段客户。服务端进行监听,客户端进行信息的发送。数据通道两端的插头。
双向通道,可读可写
Tcp编程和Udp编程都会使用到socket
案例:
1.使用字节流的形式
要求
思路
服务端处理多个socket的情况
代码
客户端
SocketTCP01Client
package com.api.socket_;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class SocketTCP01Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端Socket返回"+socket.getClass());
// 得到与socket关联的数据通道
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,server".getBytes());
// 将流关闭
outputStream.close();
socket.close();
System.out.println("客户端关闭");
}
}
服务端
SocketTCP01Server
package com.api.socket_;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCP01Server {
public static void main(String[] args) throws IOException {
// 要求电脑上没有其他程序在监听9999接口
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务器在9999端口进行监听");
//程序阻塞,不再向下执行 如果有客户端socket链接,返回一个socket链接,开始向下执行
Socket socket = serverSocket.accept();
System.out.println("客户端 socket = "+socket.getClass());
// 客户端没有发送消息的话,会堵塞在这里
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int readLine = 0 ;
while ((readLine = inputStream.read(bytes))!=-1) {
System.out.println(new String(bytes,0,readLine));//根据读取到的实际长度来读写内容
}
// 关闭socket
inputStream.close();
socket.close();
serverSocket.close(); //全部进行关闭,serverSocket可以创建很多的socket,有多个客户端来链接的情况
}
}
2.依旧是字节流案例
双向交流
服务端
SocketTCP02Server
package com.api.socket_;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCP02Server {
public static void main(String[] args) throws IOException {
// 要求电脑上没有其他程序在监听9999接口
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务器在9999端口进行监听");
//程序阻塞,不再向下执行 如果有客户端socket链接,返回一个socket链接,开始向下执行
Socket socket = serverSocket.accept();
System.out.println("客户端 socket = "+socket.getClass());
// 客户端没有发送消息的话,会堵塞在这里
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int readLine = 0 ;
while ((readLine = inputStream.read(bytes))!=-1) {
System.out.println(new String(bytes,0,readLine));//根据读取到的实际长度来读写内容
}
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,客户端".getBytes());
// 设置结束标记
socket.shutdownOutput();
// 关闭socket
outputStream.close();
inputStream.close();
socket.close();
serverSocket.close(); //全部进行关闭,serverSocket可以创建很多的socket,有多个客户端来链接的情况
}
}
运行结果
服务器在9999端口进行监听
客户端 socket = class java.net.Socket
hello,server
客户端
SocketTCP02Client
package com.api.socket_;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class SocketTCP02Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端Socket返回"+socket.getClass());
// 得到与socket关联的数据通道
OutputStream outputStream = socket.getOutputStream();
outputStream.write("hello,server".getBytes());
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int readLine = 0;
while ((readLine = inputStream.read(bytes))!=-1){
System.out.println(new String(bytes,0,readLine));
}
// 执行之后,会卡在这里,因为不知道什么时候结束。 要设计一个结束的标记
socket.shutdownInput();
// 将流关闭
inputStream.close();
outputStream.close();
socket.close();
System.out.println("客户端关闭");
}
}
客户端Socket返回class java.net.Socket
客户端关闭
最后记得设置通信结束标志socket.shutdownInput();
3.案例三,使用字符流
客户端
SocketTCP03Client
package com.api.socket_;
import javax.print.attribute.standard.OutputDeviceAssigned;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class SocketTCP03Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客户端Socket返回"+socket.getClass());
// 得到与socket关联的数据通道
OutputStream outputStream = socket.getOutputStream();
// 要求使用字符流
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("你好,服务端。。");
bufferedWriter.newLine();//对方要使用readLine来确定什么时候结束
bufferedWriter.flush();
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
bufferedReader.readLine();
System.out.println(s);
// 将流关闭 直接关闭字符流,而不是关闭字节流。
bufferedReader.close();
bufferedWriter.close();
socket.close();
System.out.println("客户端关闭...");
}
}
客户端Socket返回class java.net.Socket
hello,客户端,字符流
客户端关闭...
服务端
SocketTCP02Server
package com.api.socket_;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCP03Server {
public static void main(String[] args) throws IOException {
// 要求电脑上没有其他程序在监听9999接口
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务器在9999端口进行监听");
//程序阻塞,不再向下执行 如果有客户端socket链接,返回一个socket链接,开始向下执行
Socket socket = serverSocket.accept();
System.out.println("客户端 socket = "+socket.getClass());
// 客户端没有发送消息的话,会堵塞在这里
InputStream inputStream = socket.getInputStream();
// 使用了转换流,将字节流转化为了字符流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
OutputStream outputStream = socket.getOutputStream();
// 使用字符流来进行返回
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("hello,客户端,字符流");
// 结束标志
bufferedWriter.newLine();
// 刷新一下才会输入近数据通道
bufferedWriter.flush();
// 关闭socket
bufferedWriter.close();
bufferedReader.close();
socket.close();
serverSocket.close(); //全部进行关闭,serverSocket可以创建很多的socket,有多个客户端来链接的情况
System.out.println("服务端关闭。。。。");
}
}
服务器在9999端口进行监听
客户端 socket = class java.net.Socket
你好,服务端。。
服务端关闭。。。。
简单理一下思路:
首先分为客户端和服务端,服务端使用SocketService.accpet来创建socket。根据链接的客户端的数量创建的socket,之后创建与socket关联的流,通过相关方法,如将数据输入。一般一个端是要有输入和输出两种方法的。还有注意一下如何进行字节和字符流之间的转换,用BufferWriter来转换,之后记得是红newLine方法来表示语句结束,flush方法来刷新流,最后关闭流,有字符流就不用再关闭字节流了,后开的,先关闭。
4.使用字符流传递图片
流程图
客户端
TCPUploadClient类
package com.upload;
import com.utilty.StreamUtils;
import java.io.*;
import java.net.Socket;
public class TCPUploadClient {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("127.0.01", 8888);
// 将文件读到文件字节数组当中
String filePath = "d:\\01.jpg";
BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath));
// 得到文件对应的字节数组
byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);
// 得到socket对应的输出流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
bufferedOutputStream.write(bytes);
bufferedInputStream.close();
socket.shutdownOutput();
InputStream inputStream = socket.getInputStream();
String string = StreamUtils.streamToString(inputStream);
System.out.println(string);
inputStream.close();
bufferedOutputStream.close();
socket.close();
}
}
输出结果
已经收到了图片
服务端
TCPUpLoadService类
package com.upload;
import com.utilty.StreamUtils;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPUpLoadService {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务端在本机监听 8888 端口");
Socket socket = serverSocket.accept();
// 获得socket相关的输入流
BufferedInputStream bufferedInputStream = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bufferedInputStream);
// 将byte写入输出流
String filePath = "src\\dongman2.jpg";
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(new FileOutputStream(filePath));
bufferedOutputStream.write(bytes);
bufferedOutputStream.close();
// 向客户端返回结果通知
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferedWriter.write("已经收到了图片");
bufferedWriter.flush();
socket.shutdownOutput();
bufferedWriter.close();
bufferedInputStream.close();
socket.close();
serverSocket.close();
}
}
输出结果
服务端在本机监听 8888 端口
使用的工具类
package com.utilty;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
public class StreamUtils {
public static byte[] streamToByteArray(InputStream is) throws Exception {
// 创建输出流对象
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// 字节数组
byte[] b = new byte[1024];
int len;
while ((len = is.read(b)) != -1) {
// 循环读取
// 把读取到的数据,写入 bos
bos.write(b, 0, len);
}
byte[] array = bos.toByteArray();
bos.close();
return array;
}
public static String streamToString(InputStream is) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder builder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
builder.append(line + "\r\n");
}
return builder.toString();
}
}
5.netstat指令
三。通信协议的理解
1。tcp协议的一个小秘密
客户端也是通过一个端口来和服务端来进行链接的,但是这个端口是根据协议,随机分配的。
2.UDP网络编程(了解)
1.介绍
2.流程
UDPServiceA类
package com.UDP;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class UDPServiceA {
public static void main(String[] args) throws IOException {
//准备在9999端口等待接收数据
DatagramSocket datagramSocket = new DatagramSocket(9999);
// 最大的传送量在64kb
byte[] bytes = new byte[1024];
//
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
// 将包裹放到socket当中
System.out.println("接收端A在等待接受数据");
// 如果每有接受到数据就会阻塞
datagramSocket.receive(datagramPacket);
int length = datagramPacket.getLength();//接受字节长度
byte[] data = datagramPacket.getData(); //接收数据
String string = new String(data, 0, length);//将数据解析成字符串
System.out.println(string);
// 对要发送的数据进行封装
byte[] bytes1 = "好的,明天一定准时到".getBytes();
System.out.println("发送 :好的,明天一定准时到");
DatagramPacket datagramPacket1 = new DatagramPacket(bytes1, bytes1.length, InetAddress.getLocalHost(), 9998);
// 进行发送
datagramSocket.send(datagramPacket1);
datagramSocket.close();
}
}
接收端A在等待接受数据
明天要不要吃火锅
发送 :好的,明天一定准时到
UDPSendsB类
package com.UDP;
import java.io.IOException;
import java.net.*;
public class UDPSendsB {
public static void main(String[] args) throws IOException {
// 发送消息给A端
//在9998端口准备接收数据
DatagramSocket datagramSocket = new DatagramSocket(9998);
// 对要发送的数据进行封装
byte[] bytes = "明天要不要吃火锅".getBytes();
System.out.println("发送: 明天要不要吃火锅");
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 9999);
// 进行发送
datagramSocket.send(datagramPacket);
byte[] bytes1 = new byte[1024];
//
DatagramPacket datagramPacket1 = new DatagramPacket(bytes1, bytes.length);
// 将包裹放到socket当中
System.out.println("接收端A在等待接受数据");
// 如果每有接受到数据就会阻塞
datagramSocket.receive(datagramPacket1);
int length = datagramPacket1.getLength();//接受字节长度
byte[] data = datagramPacket1.getData(); //接收数据
String string = new String(data, 0, length);//将数据解析成字符串
System.out.println(string);
datagramSocket.close();
}
}
发送: 明天要不要吃火锅
接收端A在等待接受数据
好的,明天一定准
因为是以包的形式来发送的时候,所以会感觉UDP编程相对简单。
四。课后的作业
1。作业一
服务端
HouseWork01Server
package com.homework;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class HouseWork01Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
String name = "";
if ("name".equals(s)){
System.out.println("我的名字是tom");
}else if("hobby".equals(s)){
System.out.println("我的爱好是学习java");
}else {
System.out.println("你说的啥子!");
}
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write(name);
bufferedWriter.newLine();
bufferedWriter.flush();
bufferedWriter.close();
bufferedReader.close();
socket.close();
serverSocket.close();
System.out.println("服务端退出。。。。");
}
}
我的名字是tom
服务端退出。。。。
客户端
HouseWork01Client
package com.homework;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
public class HouseWork01Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 9999);
OutputStream outputStream = socket.getOutputStream();
// 创建字节流 字节流似乎更方便这种功能的实现
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
System.out.println("请输入你的问题");
Scanner scanner = new Scanner(System.in);
String next = scanner.next();
bufferedWriter.write(next);
bufferedWriter.newLine();
bufferedWriter.flush();
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
// 直接读取数据,以字符串的形式返回
String s = bufferedReader.readLine();
System.out.println(s);
bufferedReader.close();
bufferedWriter.close();
socket.close();
System.out.println("客户端退出。。。。");
}
}
请输入你的问题
name客户端退出。。。。
可以思考一下如何一直问,并且可以一直得到答案,除非退出。
2.课后作业二
要求
接收端
HomeWorkReceiverA
package com.homework;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class HomeWorkReceiverA {
public static void main(String[] args) throws IOException {
//准备在9999端口等待接收数据
DatagramSocket datagramSocket = new DatagramSocket(9999);
// 最大的传送量在64kb
byte[] bytes = new byte[1024];
//
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
// 将包裹放到socket当中
datagramSocket.receive(datagramPacket);
int length = datagramPacket.getLength();//接受字节长度
byte[] data = datagramPacket.getData(); //接收数据
String string = new String(data, 0, length);//将数据解析成字符串
// 判断接受到的信息是什么\
String answer = "";
if ("四大名著是那些".equals(string)){
System.out.println("四大名著有红楼梦,有三国演义,西游记。");
}else {
answer = "what";
}
// 对要发送的数据进行封装
byte[] bytes1 = answer.getBytes();
DatagramPacket datagramPacket1 = new DatagramPacket(bytes1, bytes1.length, InetAddress.getLocalHost(), 9998);
// 进行发送
datagramSocket.send(datagramPacket1);
datagramSocket.close();
System.out.println("接收端A结束");
}
}
四大名著有红楼梦,有三国演义,西游记。
接收端A结束
发送端
HomeWorkSendB
package com.homework;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class HomeWorkSendB {
public static void main(String[] args) throws IOException {
// 发送消息给A端
//在9998端口准备接收数据
DatagramSocket datagramSocket = new DatagramSocket(9998);
// 对要发送的数据进行封装
Scanner scanner = new Scanner(System.in);
System.out.println("请输入你的问题");
String next = scanner.next();
byte[] bytes = next.getBytes();
DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 9999);
// 进行发送
datagramSocket.send(datagramPacket);
byte[] bytes1 = new byte[1024];
//
DatagramPacket datagramPacket1 = new DatagramPacket(bytes1, bytes.length);
// 将包裹放到socket当中
System.out.println("接收端A在等待接受数据");
// 如果每有接受到数据就会阻塞
datagramSocket.receive(datagramPacket1);
int length = datagramPacket1.getLength();//接受字节长度
byte[] data = datagramPacket1.getData(); //接收数据
String string = new String(data, 0, length);//将数据解析成字符串
System.out.println(string);
datagramSocket.close();
}
}
请输入你的问题
四大名著是那些
接收端A在等待接受数据
3.课后作业三
要求
思路
客户端
Homework03Client类
public class Homework03Client {
public static void main(String[] args) throws Exception {
//1. 接收用户输入,指定下载文件名
Scanner scanner = new Scanner(System.in);
System.out.println("请输入下载文件名");
String downloadFileName = scanner.next();
//2. 客户端连接服务端,准备发送
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
//3. 获取和Socket关联的输出流
OutputStream outputStream = socket.getOutputStream();
outputStream.write(downloadFileName.getBytes());
//设置写入结束的标志
socket.shutdownOutput();
//4. 读取服务端返回的文件(字节数据)
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);
//5. 得到一个输出流,准备将 bytes 写入到磁盘文件
String filePath = "e:\\" + downloadFileName + ".mp3";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(filePath));
bos.write(bytes);
//6. 关闭相关的资源
bos.close();
bis.close();
outputStream.close();
socket.close();
System.out.println("客户端下载完毕..");
}
}
服务端
Homework03Server类
public class Homework03Server {
public static void main(String[] args) throws Exception {
//1 监听 9999端口
ServerSocket serverSocket = new ServerSocket(9999);
//2.等待客户端连接
System.out.println("服务端,在9999端口监听,等待下载文件");
Socket socket = serverSocket.accept();
// 使用了while读取文件名,时考虑将来客户端发送的数据较大的情况
InputStream inputStream = socket.getInputStream();
byte[] b = new byte[1024];
int len = 0;
String downLoadFileName = "";
while ((len = inputStream.read(b)) != -1) {
downLoadFileName += new String(b, 0 , len);
}
System.out.println("客户端希望下载文件名=" + downLoadFileName);
//如果客户下载的是 高山流水 我们就返回该文件,否则一律返回 无名.mp3
String resFileName = "";
if("高山流水".equals(downLoadFileName)) {
resFileName = "src\\高山流水.mp3";
} else {
resFileName = "src\\无名.mp3";
}
//4. 创建一个输入流,读取文件
BufferedInputStream bis =
new BufferedInputStream(new FileInputStream(resFileName));
//5. 使用工具类StreamUtils
byte[] bytes = StreamUtils.streamToByteArray(bis);
//6. 得到Socket关联的输出流
BufferedOutputStream bos =
new BufferedOutputStream(socket.getOutputStream());
//7. 写入到数据通道,返回给客户端
bos.write(bytes);
socket.shutdownOutput();
//8 关闭相关的资源
bis.close();
inputStream.close();
socket.close();
serverSocket.close();
System.out.println("服务端退出...");
}
}