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