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

一.服务端多任务处理

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()方法调用返回前,必须把一些数据成功传输到连接的另一端.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值