您的位置:首页 > 编程语言 > Java开发

jdk 源码分析(19)java net包简单分析

2017-11-25 14:44 357 查看

jdk 源码分析(19)java  net包简单分析

jdk 源码分析(18)java  net包只能简单分析,因为代码走到后面都变成了native方法,我去openJDK,以及其他语言的实现都没有找到底层怎么实现的,如果你知道,告诉我一声。

这里只能简单分析了。

1)通信代码:

服务端:

int port = 8919;

Socket socket =null;

ServerSocket server=null;

try {

server = new ServerSocket(port);

while(true) {

socket = server.accept();

//SocketInputStream

Reader reader = new InputStreamReader(socket.getInputStream());

char chars[] = new char[1024];

int len;

StringBuilder builder = new StringBuilder();

while ((len = reader.read(chars)) != -1) {

builder.append(new String(chars, 0, len));

}

System.out.println("Receive from client message=: " + builder);

reader.close();

}

} catch (Exception e) {

e.printStackTrace();

}finally {

try {

socket.close();

server.close();

} catch (IOException e) {

e.printStackTrace();

}

}


客户端代码:

String host = "127.0.0.1";

 int port = 8919;

try {

Socket client = new Socket(host, port);

Writer writer = new OutputStreamWriter(client.getOutputStream());

writer.write("Hello From Client");

writer.flush();

writer.close();

client.close();

} catch (IOException e) {

e.printStackTrace();

}


服务端
1)new ServerSocke
当new ServerSocket时候如果没有带入addr 将使用0.0.0.0作为默认的ip

最后new的socket 是一个native方法

PlainSocketImpl.java

static native int socket0(boolean stream, boolean v6Only)


或者TwoStacksPlainSocketImpl

native void socketCreate(boolean isServer) throws IOException;


上面两个类到底使用哪里实现类呢。下面的代码告诉我们有useDualStackImpl决定。

PlainSocketImpl() {

if (useDualStackImpl) {

impl = new DualStackPlainSocketImpl(exclusiveBind);

} else {

impl = new TwoStacksPlainSocketImpl(exclusiveBind);

}

}


这个值由系统决定。如果系统版本>=6.0或者IPV64 用DualStackPlainSocketImpl。

static {

java.security.AccessController.doPrivileged( new PrivilegedAction<Object>() {

public Object run() {

version = 0;

try {

version = Float.parseFloat(System.getProperties().getProperty("os.version"));

preferIPv4Stack = Boolean.parseBoolean(

System.getProperties().getProperty("java.net.preferIPv4Stack"));

exclBindProp = System.getProperty("sun.net.useExclusiveBind");

} catch (NumberFormatException e ) {

assert false : e;

}

return null; // nothing to return

} });



// (version >= 6.0) implies Vista or greater.

if (version >= 6.0 && !preferIPv4Stack) {

useDualStackImpl = true;

}



if (exclBindProp != null) {

// sun.net.useExclusiveBind is true

exclusiveBind = exclBindProp.length() == 0 ? true

: Boolean.parseBoolean(exclBindProp);

} else if (version < 6.0) {

exclusiveBind = false;

}

}


我的系统win7 所以有DualStackPlainSocketImpl决定。

2)accpet() 

接着accpet 也是一个native方法



void socketAccept(SocketImpl s) throws IOExce2ption {

//如果
timeout没有设置就直接进入阻塞,一直等到数据过来。会阻塞是整个线程
if (timeout <= 0) {

newfd = accept0(nativefd, isaa);

} else {

configureBlocking(nativefd, false);

try {

                //否则等待有限时间,如果没有就退出

waitForNewConnection(nativefd, timeout);

newfd = accept0(nativefd, isaa);

if (newfd != -1) {

configureBlocking(newfd, true);

}

} finally {

configureBlocking(nativefd, true);

}

}


}


这里就是io不好的地方,会一直阻塞等待,而且如果同时来了两个线程,一次只能处理一个请求。另一个只能等待了。如果一般收到一个请求后会new 一个新的线程来处理,在新的线程里完成数据读写操作。,或者线程池来处理接收的数据。

3)读写数据。

socket.getInputStream()和socket.getOutputStream()


底层定义了SocketInputStream和SocketOutputStream不过read和write也是native 的。

客服端

客户new Socket()后,会去和指定的ip和端口连接,这个又是一个native 的方法,而且会一直尝试去连接。阻塞线程。

void socketConnect(InetAddress address, int port, int timeout)

throws IOException {

int nativefd = checkAndReturnNativeFD();



if (address == null)

throw new NullPointerException("inet address argument is null.");



int connectResult;

        //不带超时的连接,

if (timeout <= 0) {

connectResult = connect0(nativefd, address, port);

} else {

            //
带超时的连接,
configureBlocking(nativefd, false);

try {

connectResult = connect0(nativefd, address, port);

if (connectResult == WOULDBLOCK) {

waitForConnect(nativefd, timeout);

}

} finally {

configureBlocking(nativefd, true);

}

}

/*

 * We need to set the local port field. If bind was called

 * previous to the connect (by the client) then localport field

 * will already be set.

 */

if (localport == 0)

localport = localPort0(nativefd);

}


net里的网络连接是阻塞的,如果服务器端使用,一般每获取一个请求后启动一个新的线程,然后由新的线程处理数据。不再服务器接收请求的那里直接处理。当然也可以像nio那样,将一个线程专门处理接收,然后启动一个线程池,专门接收数据,然后一个线程池处理数据,一个线程池会写数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐