java socket 缓冲_关于socket的发送缓冲区网上有诸多的讨论,这里个人小结一下,希望对以后有些帮助。首先,看下面一段代码,...

org.apache.tomcat.util.net包的内容都与网络连接和socket有关,比较主要和常见的是JIOEndpoint这个类,前面提到Coyote连接器的时候,就有涉及到JIOEndpoint,它用于监听某个socket端口、将socket对象交给coyote,并提供基本的线程池功能。除了JIOEndpoint,还有AprEndpoint、NioEndpoint等。由于对apr和nio不熟悉,所以只研究了一下JIOEndpoint

org.apache.tomcat.util.net.JIoEndpoint

JIOEndpoint其实和我们本科时上计算机网络或者分布式系统,做实验写的socket服务器差不多,结构也是经典的“Listen-Accept-Handle”,这里简单描述一下:JIOEndpoint使用JDK的ServerSocket类监听某个端口,有socket连接进来的时候便返回一个socket对象,交给专门的处理器。当然,具体的实现没那么简单,下面会按照socket的处理过程,详细说明其中的机理。

初始化

public void init()

throws Exception {

if (initialized)

return;

//

Initialize thread count defaults for acceptor

if

(acceptorThreadCount == 0) {

acceptorThreadCount = 1;

}

if (serverSocketFactory == null) {

serverSocketFactory = ServerSocketFactory.getDefault();

}

if (serverSocket == null) {

try {

if (address == null) {

serverSocket

= serverSocketFactory.createSocket(port, backlog);

} else {

serverSocket = serverSocketFactory.createSocket(port,

backlog, address);

}

} catch (BindException

be) {

throw new BindException(be.getMessage() + ":" + port);

}

}

//if( serverTimeout >= 0 )

//    serverSocket.setSoTimeout( serverTimeout );

initialized = true;

}

在这里,利用serverSocketFactory新建了一个serverSocket对象,用于监听特定的端口

启动JIOEndpoint

// Create worker collection

if

(executor == null) {

workers = new WorkerStack(maxThreads);

}

// Start acceptor threads

for (int i = 0; i < acceptorThreadCount; i++) {

Thread

acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i);

acceptorThread.setPriority(threadPriority);

acceptorThread.setDaemon(daemon);

acceptorThread.start();

}

这里有几个类:worker,workerStack,Acceptor。这些都是JIOEndpoint的一些内部类,下面按照处理顺序依次讲述

Acceptor内部类

Acceptor实现了Runnable接口,只有一个方法run,做的事情就是通过ServerSocket.accept方法,得到socket,然后调用JIOEndpoint的processSocket方法

protected boolean processSocket(Socket socket) {

try {

if (executor == null) {

getWorkerThread().assign(socket);

} else {

executor.execute(new SocketProcessor(socket));

}

}

catch (Throwable t) {

// This means we got an OOM or similar

creating a thread, or that

// the pool and its queue are full

log.error(sm.getString("endpoint.process.fail"), t);

return false;

}

return true;

}

在这里,JIOEndpoint有两种处理socket的方式:使用JDK5的executor,或者内部的worker类。executor怎么用大家可以直接翻书了,我们继续讨论第二种方法。

首先我们要通过getWorkerThread()方法,得到一个Worker对象。具体逻辑是,看看WorkerStack(存放所有worker的一个堆栈)里面有没有空余的worker,有则直接拿来用,无则看看能不能新建一个worker线程,假如不能(比如超出了最大线程数限制),则返回null,那样就只能委屈一下这个acceptor,稍微等一下了(wait()方法),直到有新的worker可用时,通过notify方法唤醒等待的acceptor

/**

* Return a new worker thread, and block while to

worker is available.

*/

protected Worker getWorkerThread() {

// Allocate a new worker thread

Worker workerThread =

createWorkerThread();

while (workerThread == null) {

try {

synchronized (workers) {

workers.wait();

}

} catch

(InterruptedException e) {

// Ignore

}

workerThread = createWorkerThread();

}

return workerThread;

}

如下,当有worker被回收后,通知等待的acceptor

protected void recycleWorkerThread(Worker workerThread) {

synchronized (workers) {

workers.push(workerThread);

curThreadsBusy--;

workers.notify();

}

}

ok,回到前面的processSocket方法,得到worker后,通过worker.assign方法,将socket对象传递给worker

Worker内部类

Worker也实现了runnable接口,有三个方法:assign、await、start和run

所谓的start方法,就是new一个Thread对象,把worker自己传进去,我们知道这个thread就开始执行run方法了。

public void run() {

// Process requests until we

receive a shutdown signal

while (running) {

// Wait for the next socket to be assigned

Socket socket = await();

if (socket ==

null)

continue;

// Process the

request from this socket

if (!setSocketOptions(socket) ||

!handler.process(socket)) {

// Close socket

try {

socket.close();

} catch (IOException e) {

}

}

// Finish up this request

socket = null;

recycleWorkerThread(this);

}

}

run方法首先调用await方法

private synchronized Socket await() {

// Wait for the Connector to provide a new Socket

while (!available) {

try {

wait();

} catch

(InterruptedException e) {

}

}

// Notify the Connector that we have received this Socket

Socket socket = this.socket;

available = false;

notifyAll();

return (socket);

}

通过标记位available,如果当前的worker是“非available”的,则线程会开始等待。直到我们调用的assign方法,把一个可用的socket给worker后,才会notifyall,唤醒一个线程,进而取得assign过来的socekt

synchronized void assign(Socket socket) {

// Wait

for the Processor to get the previous Socket

while (available) {

try {

wait();

}

catch (InterruptedException e) {

}

}

// Store the newly available Socket and notify our thread

this.socket = socket;

available = true;

notifyAll();

}

所以,assign和await方法相当于生产者和消费者方法,两者通过available进行互斥,而this.socket则相当于被竞争的资源

现在,又回到Worker.run方法。在取得socket后,通过setSocketOptions(socket)方法设置socket的相关选项(例如超时值),最后通过handler.process(socket),终于把socket这个接力棒交给coyote了!

handler是什么?就是个简单的接口,如下:

/**

* Bare bones interface used

for socket processing. Per thread data is to be

* stored in the

ThreadWithAttributes extra folders, or alternately in

* thread local

fields.

*/

public interface Handler {

public

boolean process(Socket socket);

}

回顾一下org.apache.coyote.http11.Http11Protocol

的Http11ConnectionHandler内部类,实现的正是这个接口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值