了解socket (套接字)之前,先要明白 webSocket 和 Socket并不是同一个东西。
(刚接触学习时候,分不清楚浪费了时间)
七层协议(OSI):是一个开放性的通信系统互连参考模型,定义得非常好的协议规范;
四层协议(TCP/IP): 发明于1970年代,在混乱的众多 网络协议中,脱颖而出;
七层模型 :7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层1 物理层;
四层模型: 4 应用层 (对应7层5/6/7) 3 传输层 2 网络层 1 数据链路层(1/2)。
Socket是传输控制层协议(TCP/UDP,都是后台交互);
WebSocket 是应用层 协议。(简单理解为页面和后台交互)
client发送方式理解为:
1找一家快递公司: (new Socket())
2 打包给女朋友礼物: 烧红的铁块 放到专用的工具(InputStream)中;
3快递发送;
4付钱关门(close);
server 的接收方式理解为:
1女友到丰巢柜盒子编码 (端口号)
2找个工具(new byte[1024])
3接收礼物
4拿完关门(close)
clinet 客户端实现:
//1创建一个socket对象(一般调用其他部门的接口,无论任何语言)
String ip = "localhost";
Integer port = 21998; // 要知道server的端口
//创建一个Socket的对象
Socket socket = new Socket(ip,port);
/*
Integer timeMax = 3 * 60 * 1000;
Socket socket1 = new Socket();//或者
socket1.setSoTimeout(timeMax);//设置阻塞的超时时间.毫秒
socket1.connect(new InetSocketAddress(ip, port), 连接时长毫秒);//连接
socket1.setKeepAlive(true);//长连接一端关闭.. 一端不关闭.会 connection reset
*/
//2获取一个IO流开始写入数据
OutputStream os = socket.getOutputStream();
os.write("发送到服务器".getBytes());
socket.shutdownOutput(); //仅仅是socket的结束标记对socket无影响
//但是如果是显示汉字就需要 字节流转成字符流(正常发送到上一步结束,只为显示发送才有这步)
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line;
while ((line = br.readLine()) != null) {System.out.println( line);}
//3 关闭(不关闭,不是大强子兄弟,会被毕业)
os.close();
socket.close();
SERVER:但是如果要提供一个Socket 接口服务
Integer port = 21998; //端口提供本机的服务端口(linux不能访问关闭防火墙)
//1创建一个Socket的对象
ServerSocket serverSocket = new ServerSocket(port);
//2得到客户端连接
Socket accept = serverSocket.accept();
//3获得流对象
InputStream is = accept.getInputStream();
int b;
while ((b=is.read()) !=-1){System.out.println((char)b);}
//读取汉字需要 字节流转换为字符流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
bw.newLine();
bw.flush();
bw.close();
accept.close();
is.close();
serverSocket.close();
线程池 实现本地图片上传;
多线程实现可以直接开启一个线程:
while (true) {
Socket accept = ss.accept();
ThreadSocket ts = new ThreadSocket(accept);
new Thread(ts).start();
}
public class ServerDuan {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10000);
ThreadPoolExecutor pool = new ThreadPoolExecutor(
3,//核心线程数量
10, //线程池的总数量
60, //临时线程空闲时间
TimeUnit.SECONDS, //临时线程空闲时间的单位
new ArrayBlockingQueue<>(5),//阻塞队列
Executors.defaultThreadFactory(),//创建线程的方式
new ThreadPoolExecutor.AbortPolicy()//任务拒绝策略
);
while (true) {
Socket accept = ss.accept();
ThreadSocket ts = new ThreadSocket(accept);
pool.submit(ts);
}
}
}
// 线程池实现
import java.io.*;
import java.net.Socket;
import java.util.UUID;
public class ThreadSocket implements Runnable {
private Socket acceptSocket;
public ThreadSocket(Socket accept) {
this.acceptSocket = accept;
}
@Override
public void run() {
BufferedOutputStream bos = null;
try {
//网络中的流,从客户端读取数据的
BufferedInputStream bis = new BufferedInputStream(acceptSocket.getInputStream());
//本地的IO流,把数据写到本地中,实现永久化存储
bos = new BufferedOutputStream(new FileOutputStream("本地测试写绝对路径" + UUID.randomUUID().toString() + ".jpg"));
int b;
while((b = bis.read()) !=-1){
bos.write(b);
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(acceptSocket.getOutputStream()));
bw.write("上传成功");
bw.newLine();
bw.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(bos != null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (acceptSocket != null){
try {
acceptSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}