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方法是一一对应的。

 

posted @ 2019-12-06 19:40  跳梁小丑李某某  阅读(827)  评论(0编辑  收藏  举报