Java Socket编程

jopen 10年前

Java Socket编程

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

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

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

每次ServerSocket</span>接收到一个新的Socket</span>连接请求后都会新起一个线程来跟当前Socket</span>进行通信,这样就达到了异步处理与客户端Socket</span>进行通信的情况。我们使用</span>BufferedReader</span>来一次读一行,而不是一次读多少字节</span>

    import java.io.BufferedReader;        import java.io.IOException;        import java.io.InputStreamReader;        import java.io.OutputStreamWriter;        import java.io.Reader;        import java.io.Writer;        import java.net.ServerSocket;        import java.net.Socket;                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();                  }               }            }  
</div> </div>
这个时候需要注意的是,BufferedReader</span>readLine</span>方法是一次读一行的,这个方法是阻塞的,直到它读到了一行数据为止程序才会继续往下执行,那么readLine</span>什么时候才会读到一行呢?直到程序遇到了换行符或者是对应流的结束符</span>readLine</span>方法才会认为读到了一行,才会结束其阻塞,让程序继续往下执行。所以我们在使用BufferedReader</span>readLine</span>读取数据的时候一定要记得在对应的输出流里面一定要写入换行符(流结束之后会自动标记为结束,readLine</span>可以识别),写入换行符之后一定记得如果输出流不是马上关闭的情况下记得flush</span>一下,这样数据才会真正的从缓冲区里面写入。对应上面的代码我们的客户端程序应该这样写:</span>


客户端:

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

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


import java.io.BufferedReader;    import java.io.InputStreamReader;    import java.io.OutputStreamWriter;    import java.io.Writer;    import java.net.Socket;    import java.net.SocketTimeoutException;        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();           }        }      
 



来自:http://haohaoxuexi.iteye.com/blog/1979837