Java Socket 编程——多线程网络聊天程序 一时失言乱红尘 2022-08-24 00:52 162阅读 0赞 首先,进行服务端的编程,作为服务端,编程主要按下面几个步骤进行: // 1. 创建socket ServerSocket ss = new ServerSocket(PortNumber); Socket s = ss.accept(); //监听器,产生阻塞,直到有连接才停止阻塞。 // 2. 打开输入流、输出流 OutputStream os = s.getOutputStream(); BufferedOutputStream bos = new BufferedOutputStream(os); InputStream is = s.getInputStream(); // 3. 根据一定的[协议][Link 1]读写数据 // [服务器][Link 2] \--> 客户 //os.write("Hello,I am Server!".getBytes()); bos.write("Hello,I am Server!".getBytes()); bos.flush(); //注意!! // [服务器][Link 2] <-- 客户 byte\[\] buf = new byte\[100\]; int len = is.read(buf); System.out.println(new String(buf, 0, len)); // 4. 关系流和Socket //os.close(); bos.close(); is.close(); s.close(); ss.close(); 作为客户端则分为下面几个步骤,其实和服务端差不多,只是少了用ServerSocket进行监听。 // 1. 创建socket Socket s = new Socket(InetAddress.getByName("localhost"), PortNumber); // 2. 打开输入流、输出流 OutputStream os = s.getOutputStream(); InputStream is = s.getInputStream(); // 3. 根据一定的[协议][Link 1]读写数据 // 服务器 --> 客户 byte\[\] buf = new byte\[100\]; int len = is.read(buf); System.out.println(new String(buf, 0, len)); // 服务器 <-- 客户 os.write("Hello,I am Client!".getBytes()); // 4. 关系流和Socket os.close(); is.close(); s.close(); 上面这些只是一个单线程的服务端->客户端的程序,只能进行一次通讯,多次通讯将被告知无法连接。 这时,我们就需要用到进程Thread进行编程,将其改造成多线程聊天程序,可以同时进行多客户端的连接与发送信息。 代码如下: 1 ![None.gif][] // Server.java 2 ![None.gif][] 3 ![None.gif][] import java.awt. \* ; 4 ![None.gif][] import java.net. \* ; 5 ![None.gif][] import java.io. \* ; 6 ![None.gif][] 7 ![ExpandedBlockStart.gif][]![ContractedBlock.gif][] public class Server extends Thread ![dot.gif][] \{ 8![InBlock.gif][] ServerSocket skt; 9![InBlock.gif][] 10![InBlock.gif][] Socket Client\[\]=new Socket\[10\];; 11![InBlock.gif][] Socket Client1=null; 12![InBlock.gif][] 13![InBlock.gif][]int i =0; 14![InBlock.gif][] 15![InBlock.gif][] TextArea in; 16![InBlock.gif][] 17![InBlock.gif][]int port,k=0,l=0; 18![InBlock.gif][] 19![InBlock.gif][]//BufferedReader theInputStream; 20![InBlock.gif][] 21![InBlock.gif][] PrintStream theOutputStream; 22![InBlock.gif][] 23![InBlock.gif][]//String readin; 24![InBlock.gif][] 25![InBlock.gif][] Face chat; 26![InBlock.gif][] 27![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]public Server(int port, Face chat) ![dot.gif][]\{ 28![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]try![dot.gif][]\{ 29![InBlock.gif][]this.port = port; 30![InBlock.gif][] skt =new ServerSocket(port); 31![InBlock.gif][]this.chat = chat; 32![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] \}catch (IOException e) ![dot.gif][]\{ 33![InBlock.gif][] chat.ta.append(e.toString()); 34![ExpandedSubBlockEnd.gif][] \} 35![ExpandedSubBlockEnd.gif][] \} 36![InBlock.gif][] 37![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicvoid run() ![dot.gif][]\{ 38![InBlock.gif][] 39![InBlock.gif][] chat.ta.append("等待连线![dot.gif][]![dot.gif][]"); 40![InBlock.gif][] 41![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]while (true) ![dot.gif][]\{ 42![InBlock.gif][]//System.out.print(""+i+"/n"); 43![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]try![dot.gif][]\{ 44![InBlock.gif][] 45![InBlock.gif][] 46![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] Client\[k\] = skt.accept(); /\*\*//\* 接收客户连接 \*/ 47![InBlock.gif][] 48![InBlock.gif][]//当有客户端连接时就新建一个子线程 49![InBlock.gif][] 50![InBlock.gif][] 51![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]if (i <2) ![dot.gif][]\{ 52![InBlock.gif][] ServerThread server\[\] =new ServerThread\[10\]; 53![InBlock.gif][] server\[k\]=new ServerThread(Client\[k\], this.chat, i); 54![InBlock.gif][] l=server.length; 55![InBlock.gif][] server\[k\].start(); 56![InBlock.gif][] chat.ta.append("客户端"\+ Client\[k\].getInetAddress() \+"已连线/n"); 57![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]/\*\*//\*theInputStream = new BufferedReader(new InputStreamReader(Client 58![ExpandedSubBlockEnd.gif][] .getInputStream()));\*/ 59![InBlock.gif][]//for(int j=0;j<server.length;j++) 60![InBlock.gif][] theOutputStream =new PrintStream(server\[k\].getClient().getOutputStream()); 61![InBlock.gif][] i = server\[k\].getI(); 62![InBlock.gif][] k\++; 63![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] \}else![dot.gif][]\{ 64![InBlock.gif][]//theOutputStream = new PrintStream(null); 65![ExpandedSubBlockEnd.gif][] \} 66![InBlock.gif][] 67![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] \}catch (SocketException e) ![dot.gif][]\{ 68![InBlock.gif][]//chat.ta.append("连线中断!/n"); 69![InBlock.gif][] 70![InBlock.gif][]//chat.clientBtn.setEnabled(true); 71![InBlock.gif][]//chat.serverBtn.setEnabled(true); 72![InBlock.gif][]//chat.tfaddress.setEnabled(true); 73![InBlock.gif][]//chat.tfport.setEnabled(true); 74![InBlock.gif][]//try \{ 75![InBlock.gif][] 76![InBlock.gif][]//skt.close(); 77![InBlock.gif][]//Client.close(); 78![InBlock.gif][]//\} catch (IOException err) \{ 79![InBlock.gif][]// chat.ta.append(err.toString()); 80![InBlock.gif][]//\} 81![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] \}catch (IOException e) ![dot.gif][]\{ 82![InBlock.gif][] chat.ta.append(e.toString()); 83![ExpandedSubBlockEnd.gif][] \} 84![ExpandedSubBlockEnd.gif][] \} 85![InBlock.gif][] 86![ExpandedSubBlockEnd.gif][] \} 87![InBlock.gif][] 88![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicvoid dataout(String data) ![dot.gif][]\{ 89![InBlock.gif][]//for(int j=0;j<l;j++) 90![InBlock.gif][] theOutputStream.println(data); 91![ExpandedSubBlockEnd.gif][] \} 92![ExpandedBlockEnd.gif][] \} 93 ![None.gif][] 94 ![ExpandedBlockStart.gif][]![ContractedBlock.gif][] class ServerThread extends Thread ![dot.gif][] \{ 95![InBlock.gif][] ServerSocket skt; 96![InBlock.gif][] 97![InBlock.gif][] Socket Client; 98![InBlock.gif][] 99![InBlock.gif][] TextArea in; 100![InBlock.gif][] 101![InBlock.gif][]int port; 102![InBlock.gif][] 103![InBlock.gif][]int i; 104![InBlock.gif][] 105![InBlock.gif][] BufferedReader theInputStream; 106![InBlock.gif][] 107![InBlock.gif][] PrintStream theOutputStream; 108![InBlock.gif][] 109![InBlock.gif][] String readin; 110![InBlock.gif][] 111![InBlock.gif][] Face chat; 112![InBlock.gif][] 113![InBlock.gif][]//服务端子线程 114![InBlock.gif][] 115![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]public ServerThread(Socket s, Face chat, int i) ![dot.gif][]\{ 116![InBlock.gif][]this.i =\++i; 117![InBlock.gif][] Client = s; 118![InBlock.gif][]//this.port = port; 119![InBlock.gif][]//skt = new ServerSocket(port); 120![InBlock.gif][]this.chat = chat; 121![InBlock.gif][] 122![ExpandedSubBlockEnd.gif][] \} 123![InBlock.gif][] 124![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicint getI() ![dot.gif][]\{ 125![InBlock.gif][]returnthis.i; 126![ExpandedSubBlockEnd.gif][] \} 127![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]public Socket getClient() ![dot.gif][]\{ 128![InBlock.gif][]returnthis.Client; 129![ExpandedSubBlockEnd.gif][] \} 130![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicvoid run() ![dot.gif][]\{ 131![InBlock.gif][] 132![InBlock.gif][]//chat.ta.append("等待连线![dot.gif][]![dot.gif][]"); 133![InBlock.gif][] 134![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]try![dot.gif][]\{ 135![InBlock.gif][]//Client = skt.accept(); /\* 接收客户连接 \*/ 136![InBlock.gif][] 137![InBlock.gif][]//chat.ta.append("客户端" + Client.getInetAddress() + "已连线/n"); 138![InBlock.gif][] theInputStream =new BufferedReader(new InputStreamReader(Client 139![InBlock.gif][] .getInputStream())); 140![InBlock.gif][] theOutputStream =new PrintStream(Client.getOutputStream()); 141![InBlock.gif][] 142![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]while (true) ![dot.gif][]\{ 143![InBlock.gif][] readin = theInputStream.readLine(); 144![InBlock.gif][] chat.ta.append(readin \+"/n"); 145![ExpandedSubBlockEnd.gif][] \} 146![InBlock.gif][] 147![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] \}catch (SocketException e) ![dot.gif][]\{ 148![InBlock.gif][] chat.ta.append("连线中断!/n"); 149![InBlock.gif][] 150![InBlock.gif][] chat.clientBtn.setEnabled(true); 151![InBlock.gif][] chat.serverBtn.setEnabled(true); 152![InBlock.gif][] chat.tfaddress.setEnabled(true); 153![InBlock.gif][] chat.tfport.setEnabled(true); 154![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]try![dot.gif][]\{ 155![InBlock.gif][] i\--; 156![InBlock.gif][] skt.close(); 157![InBlock.gif][] Client.close(); 158![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] \}catch (IOException err) ![dot.gif][]\{ 159![InBlock.gif][] chat.ta.append(err.toString()); 160![ExpandedSubBlockEnd.gif][] \} 161![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] \}catch (IOException e) ![dot.gif][]\{ 162![InBlock.gif][] chat.ta.append(e.toString()); 163![ExpandedSubBlockEnd.gif][] \} 164![ExpandedSubBlockEnd.gif][] \} 165![InBlock.gif][] 166![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicvoid dataout(String data) ![dot.gif][]\{ 167![InBlock.gif][] theOutputStream.println(data); 168![ExpandedSubBlockEnd.gif][] \} 169![ExpandedBlockEnd.gif][] \} 170 ![None.gif][] 171 ![None.gif][] // Client.java 172 ![None.gif][] 173 ![None.gif][] import java.net. \* ; 174 ![None.gif][] import java.io. \* ; 175 ![None.gif][] import javax.swing.Timer; 176 ![ExpandedBlockStart.gif][]![ContractedBlock.gif][] class Client extends Thread ![dot.gif][] \{ 177![InBlock.gif][] Socket skt; 178![InBlock.gif][] InetAddress host; 179![InBlock.gif][]int port; 180![InBlock.gif][] 181![InBlock.gif][] BufferedReader theInputStream; 182![InBlock.gif][] PrintStream theOutputStream; 183![InBlock.gif][] String readin; 184![InBlock.gif][] 185![InBlock.gif][] Face chat; 186![InBlock.gif][] 187![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]public Client(String ip, int p, Face chat) ![dot.gif][]\{ 188![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]try![dot.gif][]\{ 189![InBlock.gif][] host = InetAddress.getByName(ip); 190![InBlock.gif][] port = p; 191![InBlock.gif][]this.chat = chat; 192![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] \}catch (IOException e) ![dot.gif][]\{ 193![InBlock.gif][] chat.ta.append(e.toString()); 194![ExpandedSubBlockEnd.gif][] \} 195![ExpandedSubBlockEnd.gif][] \} 196![InBlock.gif][] 197![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicvoid run() ![dot.gif][]\{ 198![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]try![dot.gif][]\{ 199![InBlock.gif][] chat.ta.append("尝试连线![dot.gif][]![dot.gif][]"); 200![InBlock.gif][] 201![InBlock.gif][] skt =new Socket(host, port); 202![InBlock.gif][] chat.ta.append("连线成功/n"); 203![InBlock.gif][] 204![InBlock.gif][] theInputStream =new BufferedReader(new InputStreamReader(skt 205![InBlock.gif][] .getInputStream())); 206![InBlock.gif][] 207![InBlock.gif][] theOutputStream =new PrintStream(skt.getOutputStream()); 208![InBlock.gif][]//Timer myTimer = new Timer(); 209![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]while (true) ![dot.gif][]\{ 210![InBlock.gif][] readin = theInputStream.readLine(); 211![InBlock.gif][] chat.ta.append(readin \+"/n"); 212![ExpandedSubBlockEnd.gif][] \} 213![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] \}catch (SocketException e) ![dot.gif][]\{ 214![InBlock.gif][] chat.ta.append("连线中断!/n"); 215![InBlock.gif][] chat.clientBtn.setEnabled(true); 216![InBlock.gif][] chat.serverBtn.setEnabled(true); 217![InBlock.gif][] chat.tfaddress.setEnabled(true); 218![InBlock.gif][] chat.tfport.setEnabled(true); 219![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]try![dot.gif][]\{ 220![InBlock.gif][] skt.close(); 221![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] \}catch (IOException err) ![dot.gif][]\{ 222![InBlock.gif][] chat.ta.append(err.toString()); 223![ExpandedSubBlockEnd.gif][] \} 224![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] \}catch (IOException e) ![dot.gif][]\{ 225![InBlock.gif][] chat.ta.append(e.toString()); 226![ExpandedSubBlockEnd.gif][] \} 227![ExpandedSubBlockEnd.gif][] \} 228![InBlock.gif][] 229![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicvoid dataout(String data) ![dot.gif][]\{ 230![InBlock.gif][] theOutputStream.println(data); 231![ExpandedSubBlockEnd.gif][] \} 232![ExpandedBlockEnd.gif][] \} 233 ![None.gif][] 234 ![None.gif][] // 软件界面,进行按键监听调用。 235 ![None.gif][] // face.java 236 ![None.gif][] 237 ![None.gif][] import java.awt. \* ; 238 ![None.gif][] import java.awt.event. \* ; 239 ![None.gif][] 240 ![ExpandedBlockStart.gif][]![ContractedBlock.gif][] public class Face extends Frame ![dot.gif][] \{ 241![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]/\*\* \*//\*\* 242![InBlock.gif][] \* 243![ExpandedSubBlockEnd.gif][]\*/ 244![InBlock.gif][]privatestaticfinallong serialVersionUID =1L; 245![InBlock.gif][] Button clientBtn, serverBtn; 246![InBlock.gif][] TextArea ta; 247![InBlock.gif][] TextField tfaddress, tfport, tftype; 248![InBlock.gif][]int port; 249![InBlock.gif][] Client client; 250![InBlock.gif][] Server server; 251![InBlock.gif][]boolean iamserver; 252![InBlock.gif][]static Face frm; 253![InBlock.gif][] 254![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]public Face() ![dot.gif][]\{ 255![InBlock.gif][] clientBtn =new Button("客户端"); 256![InBlock.gif][] serverBtn =new Button("服务器"); 257![InBlock.gif][] ta =new TextArea("", 10, 50, TextArea.SCROLLBARS\_BOTH); 258![InBlock.gif][] tfaddress =new TextField("192.168.1.104", 20); 259![InBlock.gif][] tfport =new TextField("2000"); 260![InBlock.gif][] tftype =new TextField(50); 261![InBlock.gif][] 262![InBlock.gif][] tftype.addKeyListener(new TFListener()); 263![InBlock.gif][] ta.setEditable(false); 264![InBlock.gif][] 265![InBlock.gif][] setLayout(new FlowLayout()); 266![InBlock.gif][] add(tfaddress); 267![InBlock.gif][] add(tfport); 268![InBlock.gif][] add(clientBtn); 269![InBlock.gif][] add(serverBtn); 270![InBlock.gif][] add(ta); 271![InBlock.gif][] add(tftype); 272![InBlock.gif][] setSize(400, 300); 273![InBlock.gif][] setTitle("我的聊天室"); 274![InBlock.gif][]this.setVisible(true); 275![InBlock.gif][] 276![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] clientBtn.addActionListener(new ActionListener() ![dot.gif][]\{ 277![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicvoid actionPerformed(ActionEvent e) ![dot.gif][]\{ 278![InBlock.gif][] 279![InBlock.gif][] port = Integer.parseInt(tfport.getText()); 280![InBlock.gif][] 281![InBlock.gif][] client =new Client(tfaddress.getText(), port, frm); 282![InBlock.gif][] 283![InBlock.gif][] client.start(); 284![InBlock.gif][] 285![InBlock.gif][] tfaddress.setEnabled(false); 286![InBlock.gif][] tfport.setEnabled(false); 287![InBlock.gif][] serverBtn.setEnabled(false); 288![InBlock.gif][] clientBtn.setEnabled(false); 289![ExpandedSubBlockEnd.gif][] \} 290![ExpandedSubBlockEnd.gif][] \}); 291![InBlock.gif][] 292![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] serverBtn.addActionListener(new ActionListener() ![dot.gif][]\{ 293![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicvoid actionPerformed(ActionEvent e) ![dot.gif][]\{ 294![InBlock.gif][] 295![InBlock.gif][] port = Integer.parseInt(tfport.getText()); 296![InBlock.gif][] 297![InBlock.gif][] server =new Server(port, frm); 298![InBlock.gif][] 299![InBlock.gif][] server.start(); 300![InBlock.gif][] 301![InBlock.gif][] iamserver =true; 302![InBlock.gif][] tfaddress.setText("成为服务器"); 303![InBlock.gif][] 304![InBlock.gif][] tfaddress.setEnabled(false); 305![InBlock.gif][] tfport.setEnabled(false); 306![InBlock.gif][] serverBtn.setEnabled(false); 307![InBlock.gif][] clientBtn.setEnabled(false); 308![ExpandedSubBlockEnd.gif][] \} 309![ExpandedSubBlockEnd.gif][] \}); 310![InBlock.gif][] 311![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][] addWindowListener(new WindowAdapter() ![dot.gif][]\{ 312![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicvoid windowClosing(WindowEvent e) ![dot.gif][]\{ 313![InBlock.gif][] System.exit(0); 314![ExpandedSubBlockEnd.gif][] \} 315![ExpandedSubBlockEnd.gif][] \}); 316![InBlock.gif][] 317![ExpandedSubBlockEnd.gif][] \} 318![InBlock.gif][] 319![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicstaticvoid main(String args\[\]) ![dot.gif][]\{ 320![InBlock.gif][] frm =new Face(); 321![ExpandedSubBlockEnd.gif][] \} 322![InBlock.gif][] 323![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]privateclass TFListener implements KeyListener ![dot.gif][]\{ 324![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicvoid keyPressed(KeyEvent e) ![dot.gif][]\{ 325![InBlock.gif][] 326![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]if (e.getKeyCode() == KeyEvent.VK\_ENTER) ![dot.gif][]\{ 327![InBlock.gif][] 328![InBlock.gif][] ta.append(">"\+ tftype.getText() \+"/n"); 329![InBlock.gif][] 330![InBlock.gif][]if (iamserver) 331![InBlock.gif][] server.dataout(tftype.getText()); 332![InBlock.gif][]else 333![InBlock.gif][] client.dataout(tftype.getText()); 334![InBlock.gif][] 335![InBlock.gif][] tftype.setText(""); 336![ExpandedSubBlockEnd.gif][] \} 337![ExpandedSubBlockEnd.gif][] \} 338![InBlock.gif][] 339![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicvoid keyTyped(KeyEvent e) ![dot.gif][]\{ 340![ExpandedSubBlockEnd.gif][] \} 341![InBlock.gif][] 342![ExpandedSubBlockStart.gif][]![ContractedSubBlock.gif][]publicvoid keyReleased(KeyEvent e) ![dot.gif][]\{ 343![ExpandedSubBlockEnd.gif][] \} 344![ExpandedSubBlockEnd.gif][] \} 345![InBlock.gif][] \} [Link 1]: http://cisco.chinaitlab.com/List_11.html [Link 2]: http://server.chinaitlab.com/ [None.gif]: /images/20220823/a2bea64567054d81b15832078e0c71f8.png [ExpandedBlockStart.gif]: http://www.cnitblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif [ContractedBlock.gif]: http://www.cnitblog.com/Images/OutliningIndicators/ContractedBlock.gif [dot.gif]: /images/20220823/f7bdd0d18923498b8bed13b374ef229f.png [InBlock.gif]: /images/20220823/8619a10c22a3438daac6927ca5f5596d.png [ExpandedSubBlockStart.gif]: http://www.cnitblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif [ContractedSubBlock.gif]: /images/20220823/a2703db76e2f45a48e6265865418fce4.png [ExpandedSubBlockEnd.gif]: /images/20220823/c2b099de8f0d463cb60a18665c31322d.png [ExpandedBlockEnd.gif]: /images/20220823/eaeb712e81234c2fadc65685ea10a6b0.png
还没有评论,来说两句吧...