主页»Java WEB»Java Socket编程

Java Socket编程

来历:elim168 发布时刻:2017-06-24 阅览次数:

  关于Java Socket编程而言,有两个概念,一个是ServerSocket,一个是Socket。服务端和客户端之间经过Socket树立衔接,之后它们就可以进行通讯了。首要ServerSocket将在服务端监听某个端口,当发现客户端有Socket来企图衔接它时,它会accept该Socket的衔接恳求,一同在服务端树立一个对应的Socket与之进行通讯。这样就有两个Socket了,客户端和服务端各一个。

  关于Socket之间的通讯其实很简略,服务端往Socket的输出流里边写东西,客户端就可以经过Socket的输入流读取对应的内容。Socket与Socket之间是双向连通的,所以客户端也可以往对应的Socket输出流里边写东西,然后服务端对应的Socket的输入流就可以读出对应的内容。下面来看一些服务端与客户端通讯的比方:

 1、客户端写服务端读

  服务端代码

public class Server {  
   
   public static void main(String args[]) throws IOException {  
      //为了简略起见,一切的反常信息都往外抛  
      int port = 8899;  
      //界说一个ServerSocket监听在端口8899上  
      ServerSocket server = new ServerSocket(port);  
      //server测验接纳其他Socket的衔接恳求,server的accept办法是堵塞式的  
      Socket socket = server.accept();  
      //跟客户端树立好衔接之后,咱们就可以获取socket的InputStream,并从中读取客户端发过来的信息了。  
      Reader reader = new InputStreamReader(socket.getInputStream());  
      char chars[] = new char[64];  
      int len;  
      StringBuilder sb = new StringBuilder();  
      while ((len=reader.read(chars)) != -1) {  
         sb.append(new String(chars, 0, len));  
      }  
      System.out.println("from client: " + sb);  
      reader.close();  
      socket.close();  
      server.close();  
   }  
     
}  

  服务端从Socket的InputStream中读取数据的操作也是堵塞式的,假如从输入流中没有读取到数据程序会一向在那里不动,直到客户端往Socket的输出流中写入了数据,或封闭了Socket的输出流。当然,关于客户端的Socket也是相同如此。在操作完今后,整个程序完毕前记住封闭对应的资源,即封闭对应的IO流和Socket。

  客户端代码

public class Client {  
   
   public static void main(String args[]) throws Exception {  
      //为了简略起见,一切的反常都直接往外抛  
      String host = "127.0.0.1";  //要衔接的服务端IP地址  
      int port = 8899;   //要衔接的服务端对应的监听端口  
      //与服务端树立衔接  
      Socket client = new Socket(host, port);  
      //树立衔接后就可以往服务端写数据了  
      Writer writer = new OutputStreamWriter(client.getOutputStream());  
      writer.write("Hello Server.");  
      writer.flush();//写完后要记住flush  
      writer.close();  
      client.close();  
   }  
     
}  

  关于客户端往Socket的输出流里边写数据传递给服务端要留意一点,假如写操作之后程序不是对应着输出流的封闭,而是进行其他堵塞式的操作(比方从输入流里边读数据),记住要flush一下,只要这样服务端才干收到客户端发送的数据,不然或许会引起两头无限的相互等候。在稍后讲到客户端和服务端一同读和写的时分会提到这个问题。

 2、客户端和服务端一同读和写

  前面现已说了Socket之间是双向通讯的,它既可以接纳数据,一同也可以发送数据。

  服务端代码

public class Server {  
   
   public static void main(String args[]) throws IOException {  
      //为了简略起见,一切的反常信息都往外抛  
      int port = 8899;  
      //界说一个ServerSocket监听在端口8899上  
      ServerSocket server = new ServerSocket(port);  
      //server测验接纳其他Socket的衔接恳求,server的accept办法是堵塞式的  
      Socket socket = server.accept();  
      //跟客户端树立好衔接之后,咱们就可以获取socket的InputStream,并从中读取客户端发过来的信息了。  
      Reader reader = new InputStreamReader(socket.getInputStream());  
      char chars[] = new char[64];  
      int len;  
      StringBuilder sb = new StringBuilder();  
      while ((len=reader.read(chars)) != -1) {  
         sb.append(new String(chars, 0, len));  
      }  
      System.out.println("from client: " + sb);  
      //读完后写一句  
      Writer writer = new OutputStreamWriter(socket.getOutputStream());  
      writer.write("Hello Client.");  
      writer.flush();  
      writer.close();  
      reader.close();  
      socket.close();  
      server.close();  
   }  
     
}  

  在上述代码中首要咱们从输入流中读取客户端发送过来的数据,接下来咱们再往输出流里边写入数据给客户端,接下来封闭对应的资源文件。而实际上上述代码或许并不会依照咱们预先想象的办法运转,由于从输入流中读取数据是一个堵塞式操作,在上述的while循环中当读到数据的时分就会履行循环体,不然就会堵塞,这样后边的写操作就永久都履行不了了。除非客户端对应的Socket封闭了堵塞才会中止,while循环也会跳出。针对这种或许永久无法履行下去的状况的解决办法是while循环需求在里边有条件的跳出来,纵观上述代码,在不断改变的也只要取到的长度len和读到的数据了,len现已是不能用的了,仅有能用的便是读到的数据了。针对这种状况,一般咱们都会约好一个完毕符号,当客户端发送过来的数据包括某个完毕符号时就阐明当时的数据现已发送完毕了,这个时分咱们就可以进行循环的跳出了。那么改善后的代码会是这个姿态:

public class Server {  
   
   public static void main(String args[]) throws IOException {  
      //为了简略起见,一切的反常信息都往外抛  
      int port = 8899;  
      //界说一个ServerSocket监听在端口8899上  
      ServerSocket server = new ServerSocket(port);  
      //server测验接纳其他Socket的衔接恳求,server的accept办法是堵塞式的  
      Socket socket = server.accept();  
      //跟客户端树立好衔接之后,咱们就可以获取socket的InputStream,并从中读取客户端发过来的信息了。  
      Reader reader = new InputStreamReader(socket.getInputStream());  
      char chars[] = new char[64];  
      int len;  
      StringBuilder sb = new StringBuilder();  
      String temp;  
      int index;  
      while ((len=reader.read(chars)) != -1) {  
         temp = new String(chars, 0, len);  
         if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就完毕接纳  
            sb.append(temp.substring(0, index));  
            break;  
         }  
         sb.append(temp);  
      }  
      System.out.println("from client: " + sb);  
      //读完后写一句  
      Writer writer = new OutputStreamWriter(socket.getOutputStream());  
      writer.write("Hello Client.");  
      writer.flush();  
      writer.close();  
      reader.close();  
      socket.close();  
      server.close();  
   }  
     
}  

  在上述代码中,当服务端读取到客户端发送的完毕符号,即“eof”时就会完毕数据的接纳,停止循环,这样后续的代码又可以持续进行了。

  客户端代码

public class Client {  
   
   public static void main(String args[]) throws Exception {  
      //为了简略起见,一切的反常都直接往外抛  
     String host = "127.0.0.1";  //要衔接的服务端IP地址  
     int port = 8899;   //要衔接的服务端对应的监听端口  
     //与服务端树立衔接  
     Socket client = new Socket(host, port);  
      //树立衔接后就可以往服务端写数据了  
     Writer writer = new OutputStreamWriter(client.getOutputStream());  
      writer.write("Hello Server.");  
      writer.flush();  
      //写完今后进行读操作  
     Reader reader = new InputStreamReader(client.getInputStream());  
      char chars[] = new char[64];  
      int len;  
      StringBuffer sb = new StringBuffer();  
      while ((len=reader.read(chars)) != -1) {  
         sb.append(new String(chars, 0, len));  
      }  
      System.out.println("from server: " + sb);  
      writer.close();  
      reader.close();  
      client.close();  
   }  
     
}  

  在上述代码中咱们先是给服务端发送了一段数据,之后读取服务端回来来的数据,跟之前的服务端相同在读的进程中有或许导致程序一向挂在那里,永久跳不出while循环。这段代码协作服务端的榜首段代码就正好让咱们剖析服务端永久在那里接纳数据,永久跳不出while循环,也就没有之后的服务端回来数据给客户端,客户端也就不或许接纳到服务端回来的数据。解决办法如服务端第二段代码所示,在客户端发送数据完毕后,往输出流里边写入完毕符号告知服务端数据现已发送完毕了,相同服务端回来数据完毕后也发一个符号告知客户端。那么修改后的客户端代码就应该是这个姿态:

public class Client {  
   
   public static void main(String args[]) throws Exception {  
      //为了简略起见,一切的反常都直接往外抛  
     String host = "127.0.0.1";  //要衔接的服务端IP地址  
     int port = 8899;   //要衔接的服务端对应的监听端口  
     //与服务端树立衔接  
     Socket client = new Socket(host, port);  
      //树立衔接后就可以往服务端写数据了  
     Writer writer = new OutputStreamWriter(client.getOutputStream());  
      writer.write("Hello Server.");  
      writer.write("eof");  
      writer.flush();  
      //写完今后进行读操作  
     Reader reader = new InputStreamReader(client.getInputStream());  
      char chars[] = new char[64];  
      int len;  
      StringBuffer sb = new StringBuffer();  
      String temp;  
      int index;  
      while ((len=reader.read(chars)) != -1) {  
         temp = new String(chars, 0, len);  
         if ((index = temp.indexOf("eof")) != -1) {  
            sb.append(temp.substring(0, index));  
            break;  
         }  
         sb.append(new String(chars, 0, len));  
      }  
      System.out.println("from server: " + sb);  
      writer.close();  
      reader.close();  
      client.close();  
   }  
     
}  

  咱们日常运用的比较多的都是这种客户端发送数据给服务端,服务端接纳数据后再回来相应的成果给客户端这种办法。仅仅客户端和服务端之间不再是这种一对一的联系,而是下面要讲到的多个客户端对应同一个服务端的状况。

 3、多个客户端衔接同一个服务端

  像前面讲的两个比方都是服务端接纳一个客户端的恳求之后就完毕了,不能再接纳其他客户端的恳求了,这往往是不能满意咱们的要求的。一般咱们会这样做:

public class Server {  
   
   public static void main(String args[]) throws IOException {  
      //为了简略起见,一切的反常信息都往外抛  
     int port = 8899;  
      //界说一个ServerSocket监听在端口8899上  
     ServerSocket server = new ServerSocket(port);  
      while (true) {  
         //server测验接纳其他Socket的衔接恳求,server的accept办法是堵塞式的  
       Socket socket = server.accept();  
         //跟客户端树立好衔接之后,咱们就可以获取socket的InputStream,并从中读取客户端发过来的信息了。  
       Reader reader = new InputStreamReader(socket.getInputStream());  
         char chars[] = new char[64];  
         int len;  
         StringBuilder sb = new StringBuilder();  
         String temp;  
         int index;  
         while ((len=reader.read(chars)) != -1) {  
            temp = new String(chars, 0, len);  
            if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就完毕接纳  
                sb.append(temp.substring(0, index));  
                break;  
            }  
            sb.append(temp);  
         }  
         System.out.println("from client: " + sb);  
         //读完后写一句  
       Writer writer = new OutputStreamWriter(socket.getOutputStream());  
         writer.write("Hello Client.");  
         writer.flush();  
         writer.close();  
         reader.close();  
         socket.close();  
      }  
   }  
     
}  

  在上面代码中咱们用了一个死循环,在循环体里边ServerSocket调用其accept办法企图接纳来自客户端的衔接恳求。当没有接纳到恳求的时分,程序会在这儿堵塞直到接纳到来自客户端的衔接恳求,之后会跟当时树立好衔接的客户端进行通讯,完了后会接着履行循环体再次测验接纳新的衔接恳求。这样咱们的ServerSocket就能接纳来自一切客户端的衔接恳求了,而且与它们进行通讯了。这就完成了一个简略的一个服务端与多个客户端进行通讯的办法。

  上述比方中尽管完成了一个服务端跟多个客户端进行通讯,可是还存在一个问题。在上述比方中,咱们的服务端处理客户端的衔接恳求是同步进行的,每次接纳到来自客户端的衔接恳求后,都要先跟当时的客户端通讯完之后才干再处理下一个衔接恳求。这在并发比较多的状况下会严重影响程序的功能,为此,咱们可以把它改为如下这种异步处理与客户端通讯的办法:

public class Server {  
     
   public static void main(String args[]) throws IOException {  
      //为了简略起见,一切的反常信息都往外抛  
     int port = 8899;  
      //界说一个ServerSocket监听在端口8899上  
     ServerSocket server = new ServerSocket(port);  
      while (true) {  
         //server测验接纳其他Socket的衔接恳求,server的accept办法是堵塞式的  
         Socket socket = server.accept();  
         //每接纳到一个Socket就树立一个新的线程来处理它  
         new Thread(new Task(socket)).start();  
      }  
   }  
     
   /** 
    * 用来处理Socket恳求的 
   */  
   static class Task implements Runnable {  
   
      private Socket socket;  
        
      public Task(Socket socket) {  
         this.socket = socket;  
      }  
        
      public void run() {  
  
         try {  
  
            handleSocket();  
         } catch (Exception e) {  
            e.printStackTrace();  
         }  
      }  
        
      /** 
       * 跟客户端Socket进行通讯 
       * @throws Exception 
       */  
      private void handleSocket() throws Exception {  
         Reader reader = new InputStreamReader(socket.getInputStream());  
         char chars[] = new char[64];  
         int len;  
         StringBuilder sb = new StringBuilder();  
         String temp;  
         int index;  
         while ((len=reader.read(chars)) != -1) {  
            temp = new String(chars, 0, len);  
            if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就完毕接纳  
             sb.append(temp.substring(0, index));  
                break;  
            }  
            sb.append(temp);  
         }  
         System.out.println("from client: " + sb);  
         //读完后写一句  
       Writer writer = new OutputStreamWriter(socket.getOutputStream());  
         writer.write("Hello Client.");  
         writer.flush();  
         writer.close();  
         reader.close();  
         socket.close();  
      }  
        
   }  
     
}  

  在上面代码中,每次ServerSocket接纳到一个新的Socket衔接恳求后都会新起一个线程来跟当时Socket进行通讯,这样就到达了异步处理与客户端Socket进行通讯的状况。

  在从Socket的InputStream中接纳数据时,像上面那样一点点的读就太杂乱了,有时分咱们就会换成运用BufferedReader来一次读一行,如:

public class Server {  
   
   public static void main(String args[]) throws IOException {  
      //为了简略起见,一切的反常信息都往外抛  
     int port = 8899;  
      //界说一个ServerSocket监听在端口8899上  
     ServerSocket server = new ServerSocket(port);  
      while (true) {  
         //server测验接纳其他Socket的衔接恳求,server的accept办法是堵塞式的  
         Socket socket = server.accept();  
         //每接纳到一个Socket就树立一个新的线程来处理它  
         new Thread(new Task(socket)).start();  
      }  
   }  
     
   /** 
    * 用来处理Socket恳求的 
   */  
   static class Task implements Runnable {  
   
      private Socket socket;  
        
      public Task(Socket socket) {  
         this.socket = socket;  
      }  
        
      public void run() {  
         try {  
            handleSocket();  
         } catch (Exception e) {  
            e.printStackTrace();  
         }  
      }  
        
      /** 
       * 跟客户端Socket进行通讯 
      * @throws Exception 
       */  
      private void handleSocket() throws Exception {  
         BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));  
         StringBuilder sb = new StringBuilder();  
         String temp;  
         int index;  
         while ((temp=br.readLine()) != null) {  
            System.out.println(temp);  
            if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就完毕接纳  
             sb.append(temp.substring(0, index));  
                break;  
            }  
            sb.append(temp);  
         }  
         System.out.println("from client: " + sb);  
         //读完后写一句  
       Writer writer = new OutputStreamWriter(socket.getOutputStream());  
         writer.write("Hello Client.");  
         writer.write("eof\n");  
         writer.flush();  
         writer.close();  
         br.close();  
         socket.close();  
      }  
   }  
}  

  这个时分需求留意的是,BufferedReader的readLine办法是一次读一行的,这个办法是堵塞的,直到它读到了一行数据停止程序才会持续往下履行,那么readLine什么时分才会读到一行呢?直到程序遇到了换行符或者是对应流的完毕符readLine办法才会以为读到了一行,才会完毕其堵塞,让程序持续往下履行。所以咱们在运用BufferedReader的readLine读取数据的时分必定要记住在对应的输出流里边必定要写入换行符(流完毕之后会主动符号为完毕,readLine可以辨认),写入换行符之后必定记住假如输出流不是立刻封闭的状况下记住flush一下,这样数据才会真实的从缓冲区里边写入。对应上面的代码咱们的客户端程序应该这样写:

public class Client {  
  
   public static void main(String args[]) throws Exception {  
      //为了简略起见,一切的反常都直接往外抛  
     String host = "127.0.0.1";  //要衔接的服务端IP地址  
     int port = 8899;   //要衔接的服务端对应的监听端口  
     //与服务端树立衔接  
     Socket client = new Socket(host, port);  
      //树立衔接后就可以往服务端写数据了  
     Writer writer = new OutputStreamWriter(client.getOutputStream());  
      writer.write("Hello Server.");  
      writer.write("eof\n");  
      writer.flush();  
      //写完今后进行读操作  
     BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));  
      StringBuffer sb = new StringBuffer();  
      String temp;  
      int index;  
      while ((temp=br.readLine()) != null) {  
         if ((index = temp.indexOf("eof")) != -1) {  
            sb.append(temp.substring(0, index));  
            break;  
         }  
         sb.append(temp);  
      }  
      System.out.println("from server: " + sb);  
      writer.close();  
      br.close();  
      client.close();  
   }  
}  

 4、设置超时时刻

  假定有这样一种需求,咱们的客户端需求经过Socket从服务端获取到XX信息,然后给用户展现在页面上。咱们知道Socket在读数据的时分是堵塞式的,假如没有读到数据程序会一向堵塞在那里。在同步恳求的时分咱们肯定是不能允许这样的状况发作的,这就需求咱们在恳求到达必定的时刻后操控堵塞的中止,让程序得以持续运转。Socket为咱们供给了一个setSoTimeout()办法来设置接纳数据的超时时刻,单位是毫秒。当设置的超时时刻大于0,而且超过了这一时刻Socket还没有接纳到回来的数据的话,Socket就会抛出一个SocketTimeoutException。

  假定咱们需求操控咱们的客户端在开端读取数据10秒后还没有读到数据就中止堵塞的话咱们可以这样做:

public class Client {  
   
   public static void main(String args[]) throws Exception {  
      //为了简略起见,一切的反常都直接往外抛  
     String host = "127.0.0.1";  //要衔接的服务端IP地址  
     int port = 8899;   //要衔接的服务端对应的监听端口  
     //与服务端树立衔接  
     Socket client = new Socket(host, port);  
      //树立衔接后就可以往服务端写数据了  
     Writer writer = new OutputStreamWriter(client.getOutputStream());  
      writer.write("Hello Server.");  
      writer.write("eof\n");  
      writer.flush();  
      //写完今后进行读操作  
     BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));  
      //设置超时刻为10秒  
     client.setSoTimeout(10*1000);  
      StringBuffer sb = new StringBuffer();  
      String temp;  
      int index;  
      try {  
         while ((temp=br.readLine()) != null) {  
            if ((index = temp.indexOf("eof")) != -1) {  
                sb.append(temp.substring(0, index));  
                break;  
            }  
            sb.append(temp);  
         }  
      } catch (SocketTimeoutException e) {  
         System.out.println("数据读取超时。");  
      }  
      System.out.println("from server: " + sb);  
      writer.close();  
      br.close();  
      client.close();  
   }  
}  

 5、接纳数据乱码

  关于这种服务端或客户端接纳中文乱码的状况一般是由于数据发送时运用的编码跟接纳时分运用的编码不一致。比方有下面这样一段服务端代码:

public class Server {  
   
   public static void main(String args[]) throws IOException {  
      //为了简略起见,一切的反常信息都往外抛  
      int port = 8899;  
      //界说一个ServerSocket监听在端口8899上  
      ServerSocket server = new ServerSocket(port);  
      while (true) {  
         //server测验接纳其他Socket的衔接恳求,server的accept办法是堵塞式的  
         Socket socket = server.accept();  
         //每接纳到一个Socket就树立一个新的线程来处理它  
         new Thread(new Task(socket)).start();  
      }  
   }  
     
   /** 
    * 用来处理Socket恳求的 
    */  
   static class Task implements Runnable {  
   
      private Socket socket;  
        
      public Task(Socket socket) {  
         this.socket = socket;  
      }  
        
      public void run() {  
         try {  
            handleSocket();  
         } catch (Exception e) {  
            e.printStackTrace();  
         }  
      }  
        
      /** 
       * 跟客户端Socket进行通讯 
      * @throws Exception 
       */  
      private void handleSocket() throws Exception {  
         BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));  
         StringBuilder sb = new StringBuilder();  
         String temp;  
         int index;  
         while ((temp=br.readLine()) != null) {  
            System.out.println(temp);  
            if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就完毕接纳  
             sb.append(temp.substring(0, index));  
                break;  
            }  
            sb.append(temp);  
         }  
         System.out.println("客户端: " + sb);  
         //读完后写一句  
       Writer writer = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");  
         writer.write("你好,客户端。");  
         writer.write("eof\n");  
         writer.flush();  
         writer.close();  
         br.close();  
         socket.close();  
      }  
   }  
}  

  这儿用来测验我就弄的紊乱了一点。在上面服务端代码中咱们在界说输入流的时分清晰界说了运用GBK编码来读取数据,而在界说输出流的时分清晰指定了将运用UTF-8编码来发送数据。假如客户端上送数据的时分不以GBK编码来发送的话服务端接纳的数据就很有或许会乱码;相同假如客户端接纳数据的时分不以服务端发送数据的编码,即UTF-8编码来接纳数据的话也极有或许会呈现数据乱码的状况。所以,关于上述服务端代码,为使咱们的程序可以读取对方发送过来的数据,而不呈现乱码状况,咱们的客户端应该是这样的:

public class Client {  
   
   public static void main(String args[]) throws Exception {  
      //为了简略起见,一切的反常都直接往外抛  
     String host = "127.0.0.1";  //要衔接的服务端IP地址  
     int port = 8899;   //要衔接的服务端对应的监听端口  
     //与服务端树立衔接  
     Socket client = new Socket(host, port);  
      //树立衔接后就可以往服务端写数据了  
     Writer writer = new OutputStreamWriter(client.getOutputStream(), "GBK");  
      writer.write("你好,服务端。");  
      writer.write("eof\n");  
      writer.flush();  
      //写完今后进行读操作  
     BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));  
      //设置超时刻为10秒  
     client.setSoTimeout(10*1000);  
      StringBuffer sb = new StringBuffer();  
      String temp;  
      int index;  
      try {  
         while ((temp=br.readLine()) != null) {  
            if ((index = temp.indexOf("eof")) != -1) {  
                sb.append(temp.substring(0, index));  
                break;  
            }  
            sb.append(temp);  
         }  
      } catch (SocketTimeoutException e) {  
         System.out.println("数据读取超时。");  
      }  
      System.out.println("服务端: " + sb);  
      writer.close();  
      br.close();  
      client.close();  
   }  
}  
QQ群:凯发娱乐官网官方群(515171538),验证音讯:10000
微信群:加小编微信 849023636 邀请您参加,验证音讯:10000
提示:更多精彩内容重视微信大众号:全栈开发者中心(fsder-com)
m88 188bet uedbet 威廉希尔 明升 bwin 明升88 bodog bwin 明升m88.com 18luck 188bet unibet unibet Ladbrokes Ladbrokes casino m88明升 明升 明升 m88.com 188bet m88 明陞 uedbet赫塔菲官网 365bet官网 m88 help
188bet www.188bet.com bwin 平博 unibet 明升 188bet uk Ladbrokes 德赢vwin 188bet m88.com w88 平博88 uedbet体育 188bet 188bet 威廉希尔 明升体育app 平博88 M88 Games vwin德赢 uedbet官网 bodog fun88 188bet
网友谈论(共0条谈论) 正在载入谈论......
沉着谈论文明上网,回绝歹意咒骂 宣布谈论 / 共0条谈论
登录会员中心