Soket服务端多任务与阻塞超时

来源:互联网 发布:新的网络安全法 编辑:程序博客网 时间:2024/06/05 08:26

一.服务端多任务处理

1.先创建一个Executor实例.将接受的每个客户端Socket当一项任务,提交给Executor执行。

import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.concurrent.Executor;import java.util.concurrent.Executors;import java.util.logging.Logger;public class TCPEchoServerExecutor {    public static void main(String[] args) throws IOException {        // Create a server socket to accept client connection requests        ServerSocket servSock = new ServerSocket(9000);        Logger logger = Logger.getLogger("practical");        Executor service = Executors.newCachedThreadPool();          // Run forever, accepting and spawning threads to service each connection        while (true) {            Socket clntSock = servSock.accept(); // Block waiting for connection            service.execute(new TimeLimitEchoProtocol(clntSock, logger));        }    /* NOT REACHED */    }}

2.因为要交给Executor执行,当然要实现Runnable接口

import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import java.util.logging.Level;import java.util.logging.Logger;public class TimeLimitEchoProtocol implements Runnable {    private static final int BUFSIZE = 32;  // Size (bytes) buffer    private static final String TIMELIMIT = "10000";  // Default limit (ms)    private static final String TIMELIMITPROP = "Timelimit";  // Thread property    private static int timelimit;    private Socket clntSock;    private Logger logger;    public TimeLimitEchoProtocol(Socket clntSock, Logger logger) {        this.clntSock = clntSock;        this.logger = logger;        // Get the time limit from the System properties or take the default        timelimit = Integer.parseInt(System.getProperty(TIMELIMITPROP, TIMELIMIT));    }    public static void handleEchoClient(Socket clntSock, Logger logger) {//将之前的逻辑都搬到这里        try {            // Get the input and output I/O streams from socket            InputStream in = clntSock.getInputStream();            OutputStream out = clntSock.getOutputStream();            int recvMsgSize;                        // Size of received message            int totalBytesEchoed = 0;               // Bytes received from client            byte[] echoBuffer = new byte[BUFSIZE];  // Receive buffer            long endTime = System.currentTimeMillis() + timelimit;            int timeBoundMillis = timelimit;            clntSock.setSoTimeout(timeBoundMillis);//设置客户端处理超时时间            // Receive until client closes connection, indicated by -1            while ((timeBoundMillis > 0) &&     // catch zero values                    ((recvMsgSize = in.read(echoBuffer)) != -1)) {                out.write(echoBuffer, 0, recvMsgSize);                totalBytesEchoed += recvMsgSize;                timeBoundMillis = (int) (endTime - System.currentTimeMillis());                clntSock.setSoTimeout(timeBoundMillis);            }            logger.info("Client " + clntSock.getRemoteSocketAddress() +                    ", echoed " + totalBytesEchoed + " bytes.");        } catch (IOException ex) {            logger.log(Level.WARNING, "Exception in echo protocol", ex);        }    }    public void run() {        handleEchoClient(this.clntSock, this.logger);    }}

二.阻塞与超时处理

Socket的I/O调用可能会因为多种原因阻塞。数据输入方法read()和receive()在没有数据可读时会阻塞.Tcp socket的write()方法在没有足够的空间缓存传输的数据时可能阻塞.ServerSocket的accept()和Socket的构造函数都会阻塞,直到建立连接.
accept(),read()和receive():可以使用Socket,ServerSocket,DatagramSocket的setSoTimeout()方法,对于Socket实例,在调用read()方法前,还可以使用Socket的InputStream的available()方法检测
connect()也可以指定一个连接远程的超时时间.
write()也会阻塞,直到最后一个字节成功写入到Tcp实现的本地缓存中.如果可用的缓存空间比写入的数据小,在write()方法调用返回前,必须把一些数据成功传输到连接的另一端.

0 0
原创粉丝点击