zoukankan      html  css  js  c++  java
  • java实现hello/hi的简单的网络聊天程序与ServerSocket调用栈跟踪

    java实现hello/hi的简单的网络聊天程序

    • 网络聊天采用TCP协议通过java实现

      import java.io.*;
      import java.net.Socket;
      
      public class Client {
          public static void main(String[] args) throws Exception{
            
              Socket socket = new Socket("192.168.31.68", 6666);
      
              BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
              String s = reader.readLine();
      
              OutputStream outputStream = socket.getOutputStream();
              BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream));
              writer.write(s);
              writer.newLine();
              writer.flush();
              socket.close();
          }
      }
      
      
      import java.io.InputStream;
      import java.net.InetAddress;
      import java.net.ServerSocket;
      import java.net.Socket;
      
      
      public class SeverDemo {
          public static void main(String[] args) throws Exception{
           
              ServerSocket serverSocket = new ServerSocket(6666);
              Object i = null;
             
              while(true) {
                  Socket socket = serverSocket.accept(); 
                 
                  InputStream inputStream = socket.getInputStream();
                  
                  byte[] bytes = new byte[1024];
                  int len = inputStream.read(bytes);
                  String s = new String(bytes, 0, len);
                  InetAddress address = socket.getInetAddress();
                  System.out.println("from " + address.getHostAddress() + ": " + s);
               
                  socket.close();
              }
          }
      
      
      
    • Server

    • Client

    ServerSocket调用栈跟踪

    • 该图片描述的是socket0函数调用栈的关系
    • 从图中可以看出java从 serversocket -> 调用socketImpt -> abstractPlainSocketImpl -> DualStackSocketPlainImpl-> DualStackPlainImplt_socket0
    • 最后调用的是java中的native函数,可以在openjdk中看到(我使用的版本是openjdk 8.0)
    // windows/native/java/net/DualStackPlainSocketImpl.c
    /*
     * Class:     java_net_DualStackPlainSocketImpl
     * Method:    socket0
     * Signature: (ZZ)I
     */
    JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0
      (JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) {
        int fd, rv, opt=0;
      
    //细看可以发现,这就是我们熟悉的linux下网络编程socket的api
        fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
      
      	if (fd == INVALID_SOCKET) {
            NET_ThrowNew(env, WSAGetLastError(), "create");
            return -1;
        }
    
        rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
        if (rv == SOCKET_ERROR) {
            NET_ThrowNew(env, WSAGetLastError(), "create");
        }
    
        SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
    
        return fd;
    }
    

    • 该图片是listen函数的调用栈关系

    • ServerSocket -> abstractPlaninSocketImpl -> DualStackSocketPlainImpl-> DualStackPlainImplt_listen0

    • native关键字声明的c源码如下

      /*
       * Class:     java_net_DualStackPlainSocketImpl
       * Method:    listen0
       * Signature: (II)V
       */
      JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_listen0
        (JNIEnv *env, jclass clazz, jint fd, jint backlog) {
          if (listen(fd, backlog) == SOCKET_ERROR) {
              NET_ThrowNew(env, WSAGetLastError(), "listen failed");
          }
      }
      
      

    • 该图片为bind函数的调用栈关系
    • ServerSocket -> abstractPlaninSocketImpl -> DualStackSocketPlainImpl-> DualStackPlainImplt_bind0
    • native关键字声明的c源码如下
    /*
     * Class:     java_net_DualStackPlainSocketImpl
     * Method:    bind0
     * Signature: (ILjava/net/InetAddress;I)V
     */
    JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0
      (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
       jboolean exclBind)
    {
        SOCKETADDRESS sa;
        int rv;
        int sa_len = sizeof(sa);
    
        if (NET_InetAddressToSockaddr(env, iaObj, port, (struct sockaddr *)&sa,
                                     &sa_len, JNI_TRUE) != 0) {
          return;
        }
    
        rv = NET_WinBind(fd, (struct sockaddr *)&sa, sa_len, exclBind);
    
        if (rv == SOCKET_ERROR)
            NET_ThrowNew(env, WSAGetLastError(), "JVM_Bind");
    }
    

    • 该图片为accept函数的调用栈关系
    • ServerSocket -> abstractPlaninSocketImpl -> DualStackSocketPlainImpl-> DualStackPlainImplt_accept0
    JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0
      (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {
        int newfd, port=0;
        jobject isa;
        jobject ia;
        SOCKETADDRESS sa;
        int len = sizeof(sa);
    
        memset((char *)&sa, 0, len);
        newfd = accept(fd, (struct sockaddr *)&sa, &len);
    
        if (newfd == INVALID_SOCKET) {
            if (WSAGetLastError() == -2) {
                JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
                                "operation interrupted");
            } else {
                JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
                                "socket closed");
            }
            return -1;
        }
    
        ia = NET_SockaddrToInetAddress(env, (struct sockaddr *)&sa, &port);
        isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
        (*env)->SetObjectArrayElement(env, isaa, 0, isa);
    
        return newfd;
    }
    

    Serversocket总结

    • java底层也是调用linux 网络api实现网络通信的
    • java中Serversocket创建时就对函数进行了socket和bind和listen操作,一个函数封装了linux下3个api
    • java中的accept对应与linux下accpet函数
    • Java中Socket客户端也是类似的情况,就不做重复分析。
  • 相关阅读:
    The Fifth Week Lucklyzpp
    The Fourth Week Lucklyzpp
    The Third Week Lucklyzpp
    The Second Week lucklyzpp
    快10年没怎么过来了,一切如常
    男女诗篇
    ubuntu安装mysql
    ubuntu配置tomcat和jdk
    ubuntu常用操作命令以及它的通道模式简解
    Ubuntu操作异常汇总
  • 原文地址:https://www.cnblogs.com/HMYaa/p/12001958.html
Copyright © 2011-2022 走看看