`

Java Socket编程

 
阅读更多

原文地址:

http://haohaoxuexi.iteye.com/blog/1979837?page=2#comments

感谢博主分享!

Java Socket编程

       对于Java Socket编程而言,有两个概念,一个是ServerSocket,一个是Socket。服务端和客户端之间通过Socket建立连接,之后它们就可以进行通信了。首先ServerSocket将在服务端监听某个端口,当发现客户端有Socket来试图连接它时,它会acceptSocket的连接请求,同时在服务端建立一个对应的Socket与之进行通信。这样就有两个Socket了,客户端和服务端各一个。

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

      1、客户端写服务端读

       服务端代码

 

Java代码   收藏代码
  1. public class Server {  
  2.    
  3.    public static void main(String args[]) throws IOException {  
  4.       //为了简单起见,所有的异常信息都往外抛  
  5.       int port = 8899;  
  6.       //定义一个ServerSocket监听在端口8899上  
  7.       ServerSocket server = new ServerSocket(port);  
  8.       //server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的  
  9.       Socket socket = server.accept();  
  10.       //跟客户端建立好连接之后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了。  
  11.       Reader reader = new InputStreamReader(socket.getInputStream());  
  12.       char chars[] = new char[64];  
  13.       int len;  
  14.       StringBuilder sb = new StringBuilder();  
  15.       while ((len=reader.read(chars)) != -1) {  
  16.          sb.append(new String(chars, 0, len));  
  17.       }  
  18.       System.out.println("from client: " + sb);  
  19.       reader.close();  
  20.       socket.close();  
  21.       server.close();  
  22.    }  
  23.      
  24. }  

        

服务端从SocketInputStream中读取数据的操作也是阻塞式的,如果从输入流中没有读取到数据程序会一直在那里不动,直到客户端往Socket的输出流中写入了数据,或关闭了Socket的输出流。当然,对于客户端的Socket也是同样如此。在操作完以后,整个程序结束前记得关闭对应的资源,即关闭对应的IO流和Socket

 

       客户端代码

Java代码   收藏代码
  1. public class Client {  
  2.    
  3.    public static void main(String args[]) throws Exception {  
  4.       //为了简单起见,所有的异常都直接往外抛  
  5.       String host = "127.0.0.1";  //要连接的服务端IP地址  
  6.       int port = 8899;   //要连接的服务端对应的监听端口  
  7.       //与服务端建立连接  
  8.       Socket client = new Socket(host, port);  
  9.       //建立连接后就可以往服务端写数据了  
  10.       Writer writer = new OutputStreamWriter(client.getOutputStream());  
  11.       writer.write("Hello Server.");  
  12.       writer.flush();//写完后要记得flush  
  13.       writer.close();  
  14.       client.close();  
  15.    }  
  16.      
  17. }  

       

对于客户端往Socket的输出流里面写数据传递给服务端要注意一点,如果写操作之后程序不是对应着输出流的关闭,而是进行其他阻塞式的操作(比如从输入流里面读数据),记住要flush一下,只有这样服务端才能收到客户端发送的数据,否则可能会引起两边无限的互相等待。在稍后讲到客户端和服务端同时读和写的时候会说到这个问题。

 

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

       前面已经说了Socket之间是双向通信的,它既可以接收数据,同时也可以发送数据。

       服务端代码

 

Java代码   收藏代码
  1. public class Server {  
  2.    
  3.    public static void main(String args[]) throws IOException {  
  4.       //为了简单起见,所有的异常信息都往外抛  
  5.       int port = 8899;  
  6.       //定义一个ServerSocket监听在端口8899上  
  7.       ServerSocket server = new ServerSocket(port);  
  8.       //server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的  
  9.       Socket socket = server.accept();  
  10.       //跟客户端建立好连接之后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了。  
  11.       Reader reader = new InputStreamReader(socket.getInputStream());  
  12.       char chars[] = new char[64];  
  13.       int len;  
  14.       StringBuilder sb = new StringBuilder();  
  15.       while ((len=reader.read(chars)) != -1) {  
  16.          sb.append(new String(chars, 0, len));  
  17.       }  
  18.       System.out.println("from client: " + sb);  
  19.       //读完后写一句  
  20.       Writer writer = new OutputStreamWriter(socket.getOutputStream());  
  21.       writer.write("Hello Client.");  
  22.       writer.flush();  
  23.       writer.close();  
  24.       reader.close();  
  25.       socket.close();  
  26.       server.close();  
  27.    }  
  28.      
  29. }  

        

在上述代码中首先我们从输入流中读取客户端发送过来的数据,接下来我们再往输出流里面写入数据给客户端,接下来关闭对应的资源文件。而实际上上述代码可能并不会按照我们预先设想的方式运行,因为从输入流中读取数据是一个阻塞式操作,在上述的while循环中当读到数据的时候就会执行循环体,否则就会阻塞,这样后面的写操作就永远都执行不了了。除非客户端对应的Socket关闭了阻塞才会停止,while循环也会跳出。针对这种可能永远无法执行下去的情况的解决方法是while循环需要在里面有条件的跳出来,纵观上述代码,在不断变化的也只有取到的长度len和读到的数据了,len已经是不能用的了,唯一能用的就是读到的数据了。针对这种情况,通常我们都会约定一个结束标记,当客户端发送过来的数据包含某个结束标记时就说明当前的数据已经发送完毕了,这个时候我们就可以进行循环的跳出了。那么改进后的代码会是这个样子:

Java代码   收藏代码
  1. public class Server {  
  2.    
  3.    public static void main(String args[]) throws IOException {  
  4.       //为了简单起见,所有的异常信息都往外抛  
  5.       int port = 8899;  
  6.       //定义一个ServerSocket监听在端口8899上  
  7.       ServerSocket server = new ServerSocket(port);  
  8.       //server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的  
  9.       Socket socket = server.accept();  
  10.       //跟客户端建立好连接之后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了。  
  11.       Reader reader = new InputStreamReader(socket.getInputStream());  
  12.       char chars[] = new char[64];  
  13.       int len;  
  14.       StringBuilder sb = new StringBuilder();  
  15.       String temp;  
  16.       int index;  
  17.       while ((len=reader.read(chars)) != -1) {  
  18.          temp = new String(chars, 0, len);  
  19.          if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就结束接收  
  20.             sb.append(temp.substring(0, index));  
  21.             break;  
  22.          }  
  23.          sb.append(temp);  
  24.       }  
  25.       System.out.println("from client: " + sb);  
  26.       //读完后写一句  
  27.       Writer writer = new OutputStreamWriter(socket.getOutputStream());  
  28.       writer.write("Hello Client.");  
  29.       writer.flush();  
  30.       writer.close();  
  31.       reader.close();  
  32.       socket.close();  
  33.       server.close();  
  34.    }  
  35.      
  36. }  

       

在上述代码中,当服务端读取到客户端发送的结束标记,即“eof”时就会结束数据的接收,终止循环,这样后续的代码又可以继续进行了。

 

       客户端代码

Java代码   收藏代码
  1. public class Client {  
  2.    
  3.    public static void main(String args[]) throws Exception {  
  4.       //为了简单起见,所有的异常都直接往外抛  
  5.      String host = "127.0.0.1";  //要连接的服务端IP地址  
  6.      int port = 8899;   //要连接的服务端对应的监听端口  
  7.      //与服务端建立连接  
  8.      Socket client = new Socket(host, port);  
  9.       //建立连接后就可以往服务端写数据了  
  10.      Writer writer = new OutputStreamWriter(client.getOutputStream());  
  11.       writer.write("Hello Server.");  
  12.       writer.flush();  
  13.       //写完以后进行读操作  
  14.      Reader reader = new InputStreamReader(client.getInputStream());  
  15.       char chars[] = new char[64];  
  16.       int len;  
  17.       StringBuffer sb = new StringBuffer();  
  18.       while ((len=reader.read(chars)) != -1) {  
  19.          sb.append(new String(chars, 0, len));  
  20.       }  
  21.       System.out.println("from server: " + sb);  
  22.       writer.close();  
  23.       reader.close();  
  24.       client.close();  
  25.    }  
  26.      
  27. }  

       

在上述代码中我们先是给服务端发送了一段数据,之后读取服务端返回来的数据,跟之前的服务端一样在读的过程中有可能导致程序一直挂在那里,永远跳不出while循环。这段代码配合服务端的第一段代码就正好让我们分析服务端永远在那里接收数据,永远跳不出while循环,也就没有之后的服务端返回数据给客户端,客户端也就不可能接收到服务端返回的数据。解决方法如服务端第二段代码所示,在客户端发送数据完毕后,往输出流里面写入结束标记告诉服务端数据已经发送完毕了,同样服务端返回数据完毕后也发一个标记告诉客户端。那么修改后的客户端代码就应该是这个样子:

Java代码   收藏代码
  1. public class Client {  
  2.    
  3.    public static void main(String args[]) throws Exception {  
  4.       //为了简单起见,所有的异常都直接往外抛  
  5.      String host = "127.0.0.1";  //要连接的服务端IP地址  
  6.      int port = 8899;   //要连接的服务端对应的监听端口  
  7.      //与服务端建立连接  
  8.      Socket client = new Socket(host, port);  
  9.       //建立连接后就可以往服务端写数据了  
  10.      Writer writer = new OutputStreamWriter(client.getOutputStream());  
  11.       writer.write("Hello Server.");  
  12.       writer.write("eof");  
  13.       writer.flush();  
  14.       //写完以后进行读操作  
  15.      Reader reader = new InputStreamReader(client.getInputStream());  
  16.       char chars[] = new char[64];  
  17.       int len;  
  18.       StringBuffer sb = new StringBuffer();  
  19.       String temp;  
  20.       int index;  
  21.       while ((len=reader.read(chars)) != -1) {  
  22.          temp = new String(chars, 0, len);  
  23.          if ((index = temp.indexOf("eof")) != -1) {  
  24.             sb.append(temp.substring(0, index));  
  25.             break;  
  26.          }  
  27.          sb.append(new String(chars, 0, len));  
  28.       }  
  29.       System.out.println("from server: " + sb);  
  30.       writer.close();  
  31.       reader.close();  
  32.       client.close();  
  33.    }  
  34.      
  35. }  
  36.    

       

我们日常使用的比较多的都是这种客户端发送数据给服务端,服务端接收数据后再返回相应的结果给客户端这种形式。只是客户端和服务端之间不再是这种一对一的关系,而是下面要讲到的多个客户端对应同一个服务端的情况。

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

       像前面讲的两个例子都是服务端接收一个客户端的请求之后就结束了,不能再接收其他客户端的请求了,这往往是不能满足我们的要求的。通常我们会这样做:

Java代码   收藏代码
  1. public class Server {  
  2.    
  3.    public static void main(String args[]) throws IOException {  
  4.       //为了简单起见,所有的异常信息都往外抛  
  5.      int port = 8899;  
  6.       //定义一个ServerSocket监听在端口8899上  
  7.      ServerSocket server = new ServerSocket(port);  
  8.       while (true) {  
  9.          //server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的  
  10.        Socket socket = server.accept();  
  11.          //跟客户端建立好连接之后,我们就可以获取socket的InputStream,并从中读取客户端发过来的信息了。  
  12.        Reader reader = new InputStreamReader(socket.getInputStream());  
  13.          char chars[] = new char[64];  
  14.          int len;  
  15.          StringBuilder sb = new StringBuilder();  
  16.          String temp;  
  17.          int index;  
  18.          while ((len=reader.read(chars)) != -1) {  
  19.             temp = new String(chars, 0, len);  
  20.             if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就结束接收  
  21.                 sb.append(temp.substring(0, index));  
  22.                 break;  
  23.             }  
  24.             sb.append(temp);  
  25.          }  
  26.          System.out.println("from client: " + sb);  
  27.          //读完后写一句  
  28.        Writer writer = new OutputStreamWriter(socket.getOutputStream());  
  29.          writer.write("Hello Client.");  
  30.          writer.flush();  
  31.          writer.close();  
  32.          reader.close();  
  33.          socket.close();  
  34.       }  
  35.    }  
  36.      
  37. }  

       

在上面代码中我们用了一个死循环,在循环体里面ServerSocket调用其accept方法试图接收来自客户端的连接请求。当没有接收到请求的时候,程序会在这里阻塞直到接收到来自客户端的连接请求,之后会跟当前建立好连接的客户端进行通信,完了后会接着执行循环体再次尝试接收新的连接请求。这样我们的ServerSocket就能接收来自所有客户端的连接请求了,并且与它们进行通信了。这就实现了一个简单的一个服务端与多个客户端进行通信的模式。

       上述例子中虽然实现了一个服务端跟多个客户端进行通信,但是还存在一个问题。在上述例子中,我们的服务端处理客户端的连接请求是同步进行的,每次接收到来自客户端的连接请求后,都要先跟当前的客户端通信完之后才能再处理下一个连接请求。这在并发比较多的情况下会严重影响程序的性能,为此,我们可以把它改为如下这种异步处理与客户端通信的方式:

Java代码   收藏代码
  1. public class Server {  
  2.      
  3.    public static void main(String args[]) throws IOException {  
  4.       //为了简单起见,所有的异常信息都往外抛  
  5.      int port = 8899;  
  6.       //定义一个ServerSocket监听在端口8899上  
  7.      ServerSocket server = new ServerSocket(port);  
  8.       while (true) {  
  9.          //server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的  
  10.          Socket socket = server.accept();  
  11.          //每接收到一个Socket就建立一个新的线程来处理它  
  12.          new Thread(new Task(socket)).start();  
  13.       }  
  14.    }  
  15.      
  16.    /** 
  17.     * 用来处理Socket请求的 
  18.    */  
  19.    static class Task implements Runnable {  
  20.    
  21.       private Socket socket;  
  22.         
  23.       public Task(Socket socket) {  
  24.          this.socket = socket;  
  25.       }  
  26.         
  27.       public void run() {  
  28.   
  29.          try {  
  30.   
  31.             handleSocket();  
  32.          } catch (Exception e) {  
  33.             e.printStackTrace();  
  34.          }  
  35.       }  
  36.         
  37.       /** 
  38.        * 跟客户端Socket进行通信 
  39.        * @throws Exception 
  40.        */  
  41.       private void handleSocket() throws Exception {  
  42.          Reader reader = new InputStreamReader(socket.getInputStream());  
  43.          char chars[] = new char[64];  
  44.          int len;  
  45.          StringBuilder sb = new StringBuilder();  
  46.          String temp;  
  47.          int index;  
  48.          while ((len=reader.read(chars)) != -1) {  
  49.             temp = new String(chars, 0, len);  
  50.             if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就结束接收  
  51.              sb.append(temp.substring(0, index));  
  52.                 break;  
  53.             }  
  54.             sb.append(temp);  
  55.          }  
  56.          System.out.println("from client: " + sb);  
  57.          //读完后写一句  
  58.        Writer writer = new OutputStreamWriter(socket.getOutputStream());  
  59.          writer.write("Hello Client.");  
  60.          writer.flush();  
  61.          writer.close();  
  62.          reader.close();  
  63.          socket.close();  
  64.       }  
  65.         
  66.    }  
  67.      
  68. }  

       

在上面代码中,每次ServerSocket接收到一个新的Socket连接请求后都会新起一个线程来跟当前Socket进行通信,这样就达到了异步处理与客户端Socket进行通信的情况。

       在从SocketInputStream中接收数据时,像上面那样一点点的读就太复杂了,有时候我们就会换成使用BufferedReader来一次读一行,如:

Java代码   收藏代码
  1. public class Server {  
  2.    
  3.    public static void main(String args[]) throws IOException {  
  4.       //为了简单起见,所有的异常信息都往外抛  
  5.      int port = 8899;  
  6.       //定义一个ServerSocket监听在端口8899上  
  7.      ServerSocket server = new ServerSocket(port);  
  8.       while (true) {  
  9.          //server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的  
  10.          Socket socket = server.accept();  
  11.          //每接收到一个Socket就建立一个新的线程来处理它  
  12.          new Thread(new Task(socket)).start();  
  13.       }  
  14.    }  
  15.      
  16.    /** 
  17.     * 用来处理Socket请求的 
  18.    */  
  19.    static class Task implements Runnable {  
  20.    
  21.       private Socket socket;  
  22.         
  23.       public Task(Socket socket) {  
  24.          this.socket = socket;  
  25.       }  
  26.         
  27.       public void run() {  
  28.          try {  
  29.             handleSocket();  
  30.          } catch (Exception e) {  
  31.             e.printStackTrace();  
  32.          }  
  33.       }  
  34.         
  35.       /** 
  36.        * 跟客户端Socket进行通信 
  37.       * @throws Exception 
  38.        */  
  39.       private void handleSocket() throws Exception {  
  40.          BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));  
  41.          StringBuilder sb = new StringBuilder();  
  42.          String temp;  
  43.          int index;  
  44.          while ((temp=br.readLine()) != null) {  
  45.             System.out.println(temp);  
  46.             if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就结束接收  
  47.              sb.append(temp.substring(0, index));  
  48.                 break;  
  49.             }  
  50.             sb.append(temp);  
  51.          }  
  52.          System.out.println("from client: " + sb);  
  53.          //读完后写一句  
  54.        Writer writer = new OutputStreamWriter(socket.getOutputStream());  
  55.          writer.write("Hello Client.");  
  56.          writer.write("eof\n");  
  57.          writer.flush();  
  58.          writer.close();  
  59.          br.close();  
  60.          socket.close();  
  61.       }  
  62.    }  
  63. }  

       

这个时候需要注意的是,BufferedReaderreadLine方法是一次读一行的,这个方法是阻塞的,直到它读到了一行数据为止程序才会继续往下执行,那么readLine什么时候才会读到一行呢?直到程序遇到了换行符或者是对应流的结束符readLine方法才会认为读到了一行,才会结束其阻塞,让程序继续往下执行。所以我们在使用BufferedReaderreadLine读取数据的时候一定要记得在对应的输出流里面一定要写入换行符(流结束之后会自动标记为结束,readLine可以识别),写入换行符之后一定记得如果输出流不是马上关闭的情况下记得flush一下,这样数据才会真正的从缓冲区里面写入。对应上面的代码我们的客户端程序应该这样写:

Java代码   收藏代码
  1. public class Client {  
  2.   
  3.    public static void main(String args[]) throws Exception {  
  4.       //为了简单起见,所有的异常都直接往外抛  
  5.      String host = "127.0.0.1";  //要连接的服务端IP地址  
  6.      int port = 8899;   //要连接的服务端对应的监听端口  
  7.      //与服务端建立连接  
  8.      Socket client = new Socket(host, port);  
  9.       //建立连接后就可以往服务端写数据了  
  10.      Writer writer = new OutputStreamWriter(client.getOutputStream());  
  11.       writer.write("Hello Server.");  
  12.       writer.write("eof\n");  
  13.       writer.flush();  
  14.       //写完以后进行读操作  
  15.      BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));  
  16.       StringBuffer sb = new StringBuffer();  
  17.       String temp;  
  18.       int index;  
  19.       while ((temp=br.readLine()) != null) {  
  20.          if ((index = temp.indexOf("eof")) != -1) {  
  21.             sb.append(temp.substring(0, index));  
  22.             break;  
  23.          }  
  24.          sb.append(temp);  
  25.       }  
  26.       System.out.println("from server: " + sb);  
  27.       writer.close();  
  28.       br.close();  
  29.       client.close();  
  30.    }  
  31. }  

  

      4、设置超时时间

       假设有这样一种需求,我们的客户端需要通过Socket从服务端获取到XX信息,然后给用户展示在页面上。我们知道Socket在读数据的时候是阻塞式的,如果没有读到数据程序会一直阻塞在那里。在同步请求的时候我们肯定是不能允许这样的情况发生的,这就需要我们在请求达到一定的时间后控制阻塞的中断,让程序得以继续运行。Socket为我们提供了一个setSoTimeout()方法来设置接收数据的超时时间,单位是毫秒。当设置的超时时间大于0,并且超过了这一时间Socket还没有接收到返回的数据的话,Socket就会抛出一个SocketTimeoutException

       假设我们需要控制我们的客户端在开始读取数据10秒后还没有读到数据就中断阻塞的话我们可以这样做:

 

Java代码   收藏代码
  1. public class Client {  
  2.    
  3.    public static void main(String args[]) throws Exception {  
  4.       //为了简单起见,所有的异常都直接往外抛  
  5.      String host = "127.0.0.1";  //要连接的服务端IP地址  
  6.      int port = 8899;   //要连接的服务端对应的监听端口  
  7.      //与服务端建立连接  
  8.      Socket client = new Socket(host, port);  
  9.       //建立连接后就可以往服务端写数据了  
  10.      Writer writer = new OutputStreamWriter(client.getOutputStream());  
  11.       writer.write("Hello Server.");  
  12.       writer.write("eof\n");  
  13.       writer.flush();  
  14.       //写完以后进行读操作  
  15.      BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream()));  
  16.       //设置超时间为10秒  
  17.      client.setSoTimeout(10*1000);  
  18.       StringBuffer sb = new StringBuffer();  
  19.       String temp;  
  20.       int index;  
  21.       try {  
  22.          while ((temp=br.readLine()) != null) {  
  23.             if ((index = temp.indexOf("eof")) != -1) {  
  24.                 sb.append(temp.substring(0, index));  
  25.                 break;  
  26.             }  
  27.             sb.append(temp);  
  28.          }  
  29.       } catch (SocketTimeoutException e) {  
  30.          System.out.println("数据读取超时。");  
  31.       }  
  32.       System.out.println("from server: " + sb);  
  33.       writer.close();  
  34.       br.close();  
  35.       client.close();  
  36.    }  
  37. }  
  38.   
  39.    

       5、接收数据乱码

       对于这种服务端或客户端接收中文乱码的情况通常是因为数据发送时使用的编码跟接收时候使用的编码不一致。比如有下面这样一段服务端代码:

Java代码   收藏代码
  1. public class Server {  
  2.    
  3.    public static void main(String args[]) throws IOException {  
  4.       //为了简单起见,所有的异常信息都往外抛  
  5.       int port = 8899;  
  6.       //定义一个ServerSocket监听在端口8899上  
  7.       ServerSocket server = new ServerSocket(port);  
  8.       while (true) {  
  9.          //server尝试接收其他Socket的连接请求,server的accept方法是阻塞式的  
  10.          Socket socket = server.accept();  
  11.          //每接收到一个Socket就建立一个新的线程来处理它  
  12.          new Thread(new Task(socket)).start();  
  13.       }  
  14.    }  
  15.      
  16.    /** 
  17.     * 用来处理Socket请求的 
  18.     */  
  19.    static class Task implements Runnable {  
  20.    
  21.       private Socket socket;  
  22.         
  23.       public Task(Socket socket) {  
  24.          this.socket = socket;  
  25.       }  
  26.         
  27.       public void run() {  
  28.          try {  
  29.             handleSocket();  
  30.          } catch (Exception e) {  
  31.             e.printStackTrace();  
  32.          }  
  33.       }  
  34.         
  35.       /** 
  36.        * 跟客户端Socket进行通信 
  37.       * @throws Exception 
  38.        */  
  39.       private void handleSocket() throws Exception {  
  40.          BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(), "GBK"));  
  41.          StringBuilder sb = new StringBuilder();  
  42.          String temp;  
  43.          int index;  
  44.          while ((temp=br.readLine()) != null) {  
  45.             System.out.println(temp);  
  46.             if ((index = temp.indexOf("eof")) != -1) {//遇到eof时就结束接收  
  47.              sb.append(temp.substring(0, index));  
  48.                 break;  
  49.             }  
  50.             sb.append(temp);  
  51.          }  
  52.          System.out.println("客户端: " + sb);  
  53.          //读完后写一句  
  54.        Writer writer = new OutputStreamWriter(socket.getOutputStream(), "UTF-8");  
  55.          writer.write("你好,客户端。");  
  56.          writer.write("eof\n");  
  57.          writer.flush();  
  58.          writer.close();  
  59.          br.close();  
  60.          socket.close();  
  61.       }  
  62.    }  
  63. }  

       

这里用来测试我就弄的混乱了一点。在上面服务端代码中我们在定义输入流的时候明确定义了使用GBK编码来读取数据,而在定义输出流的时候明确指定了将使用UTF-8编码来发送数据。如果客户端上送数据的时候不以GBK编码来发送的话服务端接收的数据就很有可能会乱码;同样如果客户端接收数据的时候不以服务端发送数据的编码,即UTF-8编码来接收数据的话也极有可能会出现数据乱码的情况。所以,对于上述服务端代码,为使我们的程序能够读取对方发送过来的数据,而不出现乱码情况,我们的客户端应该是这样的:

Java代码   收藏代码
  1. public class Client {  
  2.    
  3.    public static void main(String args[]) throws Exception {  
  4.       //为了简单起见,所有的异常都直接往外抛  
  5.      String host = "127.0.0.1";  //要连接的服务端IP地址  
  6.      int port = 8899;   //要连接的服务端对应的监听端口  
  7.      //与服务端建立连接  
  8.      Socket client = new Socket(host, port);  
  9.       //建立连接后就可以往服务端写数据了  
  10.      Writer writer = new OutputStreamWriter(client.getOutputStream(), "GBK");  
  11.       writer.write("你好,服务端。");  
  12.       writer.write("eof\n");  
  13.       writer.flush();  
  14.       //写完以后进行读操作  
  15.      BufferedReader br = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));  
  16.       //设置超时间为10秒  
  17.      client.setSoTimeout(10*1000);  
  18.       StringBuffer sb = new StringBuffer();  
  19.       String temp;  
  20.       int index;  
  21.       try {  
  22.          while ((temp=br.readLine()) != null) {  
  23.             if ((index = temp.indexOf("eof")) != -1) {  
  24.                 sb.append(temp.substring(0, index));  
  25.                 break;  
  26.             }  
  27.             sb.append(temp);  
  28.          }  
  29.       } catch (SocketTimeoutException e) {  
  30.          System.out.println("数据读取超时。");  
  31.       }  
  32.       System.out.println("服务端: " + sb);  
  33.       writer.close();  
  34.       br.close();  
  35.       client.close();  
  36.    }  
  37. }  

  

分享到:
评论

相关推荐

    java socket编程

    Java Socket编程是Java平台中用于实现网络通信的核心API,它基于TCP/IP协议栈,提供了低级别的、面向连接的、可靠的字节流通信。在本文中,我们将深入探讨Java Socket编程的关键概念、工作原理以及如何创建服务端和...

    Java socket编程实现两台主机间的通信

    Java Socket 编程实现两台主机间的通信 Java Socket 编程是 Java 语言中用于实现网络通信的编程技术。通过使用 Socket 编程,可以实现两台主机之间的通信,实现数据的传输和交换。本文将详细介绍 Java Socket 编程...

    java socket 编程

    java socket编程 java网络编程 课件 java socket编程 java网络编程 课件

    JAVA Socket编程实现文件上传

    Java Socket编程是网络编程的基础,它提供了在两个应用程序之间建立通信连接的能力。在这个场景中,我们讨论的是如何使用Java的Socket来实现文件上传功能,即从客户端将文件发送到服务器,然后保存到服务器的数据库...

    java socket 编程,Java socket 编程实例

    ### Java Socket编程详解及实例分析 #### 一、Socket编程基础概述 在计算机网络通信领域,Socket编程是一种广泛使用的通信方式。它为不同主机上的进程提供了双向通信的能力,是网络编程的基础之一。Java语言提供了...

    Java Socket 编程html教程

    Java Socket编程是Java网络编程的重要组成部分,主要用于实现客户端与服务器之间的通信。在本文中,我们将深入探讨Java Socket编程的基础知识,以及如何结合HTML进行交互。 首先,Java Socket是TCP/IP协议族的一...

    Java Socket 编程源代码示例

    import java.io.*; import java.net.*; import java.util.*; import java.lang.*; public class Server extends ServerSocket { private static ArrayList User_List = new ArrayList(); private static ...

    java socket 编程文档

    本文将深入探讨Java Socket编程的基础知识、关键概念以及如何在实践中应用。 一、Socket概述 Socket,也被称为套接字,是网络通信的端点,可以理解为两个应用程序之间的连接通道。在Java中,Socket类(java.net....

    华科-计算机网络实验报告-Java Socket编程-网络组建实验.docx

    Java Socket 编程在计算机网络实验中的应用 Java Socket 编程是计算机网络实验中的一个重要组成部分,它允许开发者创建可以在网络上传输数据的应用程序。下面是关于 Java Socket 编程在计算机网络实验中的应用的...

    总结java_socket编程.doc

    在Java中,Socket编程主要是基于TCP/IP协议的网络编程。 网络编程的两个主要问题 在网络编程中,有两个主要的问题需要解决:一是如何准确地定位网络上的一台或多台主机,二是找到主机后如何可靠高效地进行数据传输...

    Java Socket编程:文件传输.doc

    Java Socket 编程:文件传输 Java Socket 编程是 Java 语言中的一种网络编程技术,用于实现客户端和服务器端之间的数据传输。文件传输是 Java Socket 编程中的一种常见应用场景,通过建立客户端和服务器端之间的...

    Java socket编程实例.pdf

    本文将通过一个具体的Java Socket编程实例来深入探讨如何使用Java实现客户端与服务端之间的通信。 #### 二、基础知识概述 在开始具体实例之前,我们需要了解一些基本概念: - **Socket**:Socket是一种用于在网络...

    java Socket 编程源码

    Java Socket编程是网络编程的基础,它提供了在Java中进行低级网络通信的接口。Socket是TCP/IP协议族的一部分,用于实现客户端与服务器之间的双向通信。在这个"java TCP_IP Socket 编程"源码中,我们可以深入理解...

    java socket编程实例(出自《java大学教程》)

    学习这些Java Socket编程实例,有助于理解TCP/IP通信的基本原理,为构建实际的网络应用程序打下坚实的基础。你可以通过调试和修改`SocketTest`代码,进一步探索和实践Socket编程的不同场景,如文件传输、聊天应用等...

    浅出Java Socket编程

    Java Socket编程是网络编程的基础,它是Java平台中用于实现客户端-服务器通信的关键组件。本教程将深入浅出地探讨Java Socket编程的核心概念和技术,帮助开发者理解如何构建可靠的网络应用程序。 一、Socket概述 ...

    Java Socket编程笔记_动力节点Java学院整理

    异常处理在Java Socket编程中扮演着重要角色。主要涉及四种异常类型: 1. `UnknownHostException`: 表示主机名或IP地址无法解析,通常是因为网络不可达或者主机名不存在。 2. `ConnectException`: 当尝试连接到...

    Java Socket编程.pdf

    Java Socket编程是网络编程的一个重要部分,它允许在网络中的计算机之间进行数据交换。Socket编程是基于TCP/IP协议的,因此了解计算机网络、分组报文和协议对于掌握Socket编程来说至关重要。接下来,我将详细解释...

    Java Socket网络编程.pdf

    在Java中,Socket编程主要涉及两个关键类:`ServerSocket`和`Socket`。`ServerSocket`类用于服务器端,它监听指定端口的连接请求。创建一个`ServerSocket`实例,例如`ServerSocket server = new ServerSocket(9998);...

    三步学会Java_Socket编程

    在Java中,Socket编程是实现网络通信的基础,它提供了进程间通信的能力,使得两个相隔万里的计算机可以通过互联网进行数据交换。本篇文章将深入讲解如何通过三步学习Java Socket编程。 **第一步:理解Socket** ...

    JAVA Socket 经典教程

    本教程将深入探讨Java Socket编程的核心概念,以及如何利用它进行网络通信。 1. **Java Socket基础** - **Socket的概念**:Socket是网络通信中的一个端点,可以理解为两台机器间通信的桥梁。在Java中,Socket类...

Global site tag (gtag.js) - Google Analytics