zoukankan      html  css  js  c++  java
  • Java的socket通信与操作系统的SocketAPI关系探究

    Java使用Socket的通信过程

     1.服务器端socket绑定端口,并一直监听该端口,等待客户端的连接

    2.客户端绑定一个端口,并通过套接字连接服务器端等待服务的端口

    3.连接成功后,服务器端和客户端通过建立的连接进行通信

    4.一端关闭连接,另一端捕捉异常通信结束。

    使用Java代码实现上述的通信过程:

    客户端代码:

    package chat2;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.util.Scanner;
    
    public class ClientSocket {
        public static void main(String[] args) throws Exception {
            try {
                System.out.println("聊天开始");
                while (true) {
                    Socket client_socket = new Socket(InetAddress.getLocalHost(), 4856);
     
                    OutputStream os = client_socket.getOutputStream();
    
                    Scanner sc = new Scanner(System.in);
                    String str = sc.nextLine();
                    char flag = str.charAt(0);
                    os.write(str.getBytes());
                    client_socket.shutdownOutput();
     
                    InputStream is = client_socket.getInputStream();
     
                    byte[] data = new byte[1024];
                    int len = 0;
                    while ((len = is.read(data)) != -1) {
                        System.out.println("服务器说"+new String(data, 0, len));
                    }
                    printStack();
                    is.close();
                    os.close();
                    client_socket.close();
                    Thread.sleep(200);
                }
            } catch (Exception e) {
                System.out.println("聊天结束");
                System.exit(0);
            }
        }
        public static void printStack() {
            StackTraceElement[] element = Thread.currentThread().getStackTrace();
            for (int i = 0 ;i < element.length; i++){
                System.out.println(element[i].getClassName()+" 。"+element[i].getMethodName()+"-----");
            }
        }
    }

    服务器端代码:

    package chat2;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Scanner;
    
    public class Server {
    
        public static void main(String[] args) throws Exception {
            try {
                System.out.println("开始聊天");
                ServerSocket serverSocket = new ServerSocket(4856);
                ClientSocket.printStack();
                while (true) {
     
                    Socket accept = serverSocket.accept();
                    InputStream is = accept.getInputStream();
     
                    byte[] data = new byte[1024];
                    int len = 0;
                    
                    while ((len = is.read(data)) != -1) {
                        System.out.println("客户端说"+new String(data, 0, len));
                    }
     
                    Scanner sc = new Scanner(System.in);
                    String str = sc.nextLine();
                    char flag = str.charAt(0);
    
                    OutputStream os = accept.getOutputStream();
                    os.write(str.getBytes());
                    ClientSocket.printStack();
                    accept.shutdownOutput();
                    is.close();
                    os.close();
                    accept.close();
                }
            } catch (Exception e) {
                System.out.println("聊天结束");
                System.exit(0);
            }
    
    }
    }

    常用的操作系统的Socket通信API

    1.bind

    int bind(
     __in          SOCKET s, //.指定一个未绑定的socket。
     __in          const struct sockaddr* name,//指向sockaddr地址的指针,该结构含有IP和PORT
    __in          int namelen  //Length of the value in the name parameter, in bytes。
     ); 

    2.listen

    int listen(
      __in          SOCKET s, //socket描述符,该socket是一个未连接状态的socket
      __in          int backlog //挂起连接的最大长度,如果该值设置为SOMAXCONN,负责socket的底部服务提供商将设置该值为最大合理值。并没有该值的明确规定。
    );

    3.accpet

    SOCKET accept(
       __in          SOCKET s, //listen函数用到的socket。accept函数将创建连接。
       __out         struct sockaddr* addr, //指向通信层连接实体地址的指针。
       __in_out      int* addrlen    //addr的长度。
     );

    4.connect

    int connect(
       __in          SOCKET s,
       __in          const struct sockaddr* name,//指明待连接的地址
       __in          int namelen
     );

    Java的Socket通信与底层C语言的Socket通信的关系:

    分析服务器端的

    ServerSocket serverSocket = new ServerSocket(4856);

    所对应的C语言Socket源码,java中该语句的作用是创建一个socket并为其绑定对应的端口。

    查看JDK中源码,对该方法进行追溯,可得到其最终调用了两个本地方法:

     

      static native void bind0(int fd, InetAddress localAddress, int localport,
                                 boolean exclBind)
            throws IOException;
        static native void listen0(int fd, int backlog) throws IOException;

    而服务器端的代码

    Socket accept = serverSocket.accept();

    的作用是阻塞自己并接收请求。查看JDK中源码,对该方法进行追溯,其调用本地方法:

     static native int accept0(int fd, InetSocketAddress[] isaa) throws IOException;

    对客户端代码

    Socket client_socket = new Socket(InetAddress.getLocalHost(), 4856);

    ,其中用是与对应的socket连接并进行通信,对其进行源码分析可追溯到:

    即调用的:

        static native int connect0(int fd, InetAddress remote, int remotePort)
            throws IOException;

    JavaNative方法与操作系统的Socket方法关系分析:

    以上JavaSocket所调用的native方法即为对应的C方法。native方法再虚拟机上执行,即调用操作系统的Socket通信方法。

    即整个流程就是Java方法调用C语言写的Native方法,native方法再虚拟机执行调用操作系统的socket方法。即java的native方法与winsock.dll中的操作系统socket方法是一一对应的。

  • 相关阅读:
    Linux中Shell的算数运算符和位运算符用法笔记
    Linux中Shell的算数运算符和位运算符用法笔记
    Linux中Shell的命令替换用法笔记
    Linux中Shell的命令替换用法笔记
    Linux中shell变量作用域笔记
    Linux中shell变量作用域笔记
    模块进阶、标准库、扩展库
    模块的导入
    私有化
    python作用域与LEGB规则
  • 原文地址:https://www.cnblogs.com/tlxclmm/p/11997222.html
Copyright © 2011-2022 走看看