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

来源:互联网 发布:怎么样开淘宝网店 编辑:程序博客网 时间:2024/06/10 02:15
jdk 源码分析(18)java  net包只能简单分析,因为代码走到后面都变成了native方法,我去openJDK,以及其他语言的实现都没有找到底层怎么实现的,如果你知道,告诉我一声。
这里只能简单分析了。

1)通信代码:
服务端:
  1. int port = 8919;
  2. Socket socket =null;
  3. ServerSocket server=null;
  4. try {
  5. server = new ServerSocket(port);
  6. while(true) {
  7. socket = server.accept();
  8. //SocketInputStream
  9. Reader reader = new InputStreamReader(socket.getInputStream());
  10. char chars[] = new char[1024];
  11. int len;
  12. StringBuilder builder = new StringBuilder();
  13. while ((len = reader.read(chars)) != -1) {
  14. builder.append(new String(chars, 0, len));
  15. }
  16. System.out.println("Receive from client message=: " + builder);
  17. reader.close();
  18. }
  19. } catch (Exception e) {
  20. e.printStackTrace();
  21. }finally {
  22. try {
  23. socket.close();
  24. server.close();
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. }
  28. }
客户端代码:
  1. String host = "127.0.0.1";
  2. int port = 8919;
  3. try {
  4. Socket client = new Socket(host, port);
  5. Writer writer = new OutputStreamWriter(client.getOutputStream());
  6. writer.write("Hello From Client");
  7. writer.flush();
  8. writer.close();
  9. client.close();
  10. } catch (IOException e) {
  11. e.printStackTrace();
  12. }
服务端
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决定。
  1. PlainSocketImpl() {
  2. if (useDualStackImpl) {
  3. impl = new DualStackPlainSocketImpl(exclusiveBind);
  4. } else {
  5. impl = new TwoStacksPlainSocketImpl(exclusiveBind);
  6. }
  7. }
这个值由系统决定。如果系统版本>=6.0或者IPV64 用DualStackPlainSocketImpl。
  1. static {
  2. java.security.AccessController.doPrivileged( new PrivilegedAction<Object>() {
  3. public Object run() {
  4. version = 0;
  5. try {
  6. version = Float.parseFloat(System.getProperties().getProperty("os.version"));
  7. preferIPv4Stack = Boolean.parseBoolean(
  8. System.getProperties().getProperty("java.net.preferIPv4Stack"));
  9. exclBindProp = System.getProperty("sun.net.useExclusiveBind");
  10. } catch (NumberFormatException e ) {
  11. assert false : e;
  12. }
  13. return null; // nothing to return
  14. } });
  15. // (version >= 6.0) implies Vista or greater.
  16. if (version >= 6.0 && !preferIPv4Stack) {
  17. useDualStackImpl = true;
  18. }
  19. if (exclBindProp != null) {
  20. // sun.net.useExclusiveBind is true
  21. exclusiveBind = exclBindProp.length() == 0 ? true
  22. : Boolean.parseBoolean(exclBindProp);
  23. } else if (version < 6.0) {
  24. exclusiveBind = false;
  25. }
  26. }
我的系统win7 所以有DualStackPlainSocketImpl决定。
2)accpet() 
接着accpet 也是一个native方法
  1. void socketAccept(SocketImpl s) throws IOExce2ption {
  2. //如果timeout没有设置就直接进入阻塞,一直等到数据过来。会阻塞是整个线程
  3. if (timeout <= 0) {
  4. newfd = accept0(nativefd, isaa);
  5. } else {
  6. configureBlocking(nativefd, false);
  7. try {
  8.                 //否则等待有限时间,如果没有就退出
  9. waitForNewConnection(nativefd, timeout);
  10. newfd = accept0(nativefd, isaa);
  11. if (newfd != -1) {
  12. configureBlocking(newfd, true);
  13. }
  14. } finally {
  15. configureBlocking(nativefd, true);
  16. }
  17. }
  18. }
这里就是io不好的地方,会一直阻塞等待,而且如果同时来了两个线程,一次只能处理一个请求。另一个只能等待了。如果一般收到一个请求后会new 一个新的线程来处理,在新的线程里完成数据读写操作。,或者线程池来处理接收的数据。

3)读写数据。
socket.getInputStream()和socket.getOutputStream()
底层定义了SocketInputStream和SocketOutputStream不过read和write也是native 的。

客服端
客户new Socket()后,会去和指定的ip和端口连接,这个又是一个native 的方法,而且会一直尝试去连接。阻塞线程。
  1. void socketConnect(InetAddress address, int port, int timeout)
  2. throws IOException {
  3. int nativefd = checkAndReturnNativeFD();
  4. if (address == null)
  5. throw new NullPointerException("inet address argument is null.");
  6. int connectResult;
  7.         //不带超时的连接,
  8. if (timeout <= 0) {
  9. connectResult = connect0(nativefd, address, port);
  10. } else {
  11.             //带超时的连接,
  12. configureBlocking(nativefd, false);
  13. try {
  14. connectResult = connect0(nativefd, address, port);
  15. if (connectResult == WOULDBLOCK) {
  16. waitForConnect(nativefd, timeout);
  17. }
  18. } finally {
  19. configureBlocking(nativefd, true);
  20. }
  21. }
  22. /*
  23. * We need to set the local port field. If bind was called
  24. * previous to the connect (by the client) then localport field
  25. * will already be set.
  26. */
  27. if (localport == 0)
  28. localport = localPort0(nativefd);
  29. }


net里的网络连接是阻塞的,如果服务器端使用,一般每获取一个请求后启动一个新的线程,然后由新的线程处理数据。不再服务器接收请求的那里直接处理。当然也可以像nio那样,将一个线程专门处理接收,然后启动一个线程池,专门接收数据,然后一个线程池处理数据,一个线程池会写数据。


原创粉丝点击