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