先上一张网络聊天程序运行图:
功能实现的很简单,客户端输入服务器IP和端口信息连接服务器,建立连接之后,客户端和服务器就可以进行双向通信了。
源码如下:
client端 源代码
import java.io.*;importjava.net.Socket;importjava.util.Scanner;public class Client extends Netutil implementsRunnable{
String IPAdress;intport;
Client(String IPAdress,intport){this.IPAdress=IPAdress;this.port=port;
}public static voidmain(String[] args) {
Scanner scanner= newScanner(System.in);
System.out.print("请输入IP地址:");
String ip=scanner.nextLine();
System.out.print("请输入端口号:");int port=scanner.nextInt();
Client client1=newClient(ip,port);
Thread thread1=newThread(client1);
thread1.start();
}
@Overridepublic voidrun() {try{
Socket s= new Socket(this.IPAdress, this.port);super.Oprate(s);
}catch(IOException e) {
e.printStackTrace();
}
}
}
Server端源代码:
import java.io.*;importjava.net.InetAddress;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.Scanner;public class Server extendsNetutil {public static voidmain(String[] args) {newServer().Get();
}/*进入的方法*/
public voidGet() {try{
ServerSocket serverSocket= new ServerSocket(4432);
InetAddress inetAddress=InetAddress.getLocalHost();//System.out.println("开启服务器");
System.out.println("地址:" + inetAddress.getHostAddress() + "端口:" + 4432);
Socket accept;while (true) {
accept=serverSocket.accept();//System.out.println("主机"+accept.getRemoteSocketAddress()+"连接服务器");
Thread hander= new Thread(newHandler(accept));
hander.start();
}
}catch(IOException e) {
e.printStackTrace();
}
}/*** 内部处理类*/
class Handler extends Netutil implementsRunnable {
Socket socket;publicHandler(Socket socket) {this.socket =socket;
}
@Overridepublic voidrun() {try{super.Oprate(socket);
}catch(IOException e) {
e.printStackTrace();
}
}
}
}
聊天功能实现类:
importjava.io.DataInputStream;importjava.io.DataOutputStream;importjava.io.IOException;importjava.net.Socket;importjava.util.Scanner;public classNetutil {public void Oprate(Socket s) throwsIOException {
DataInputStream dataInputStream= newDataInputStream(s.getInputStream());
DataOutputStream dataOutputStream= newDataOutputStream(s.getOutputStream());newThread() {
@Overridepublic voidrun() {
String line;
String content= "";while (true) {try{
Thread.sleep(100);
content= "";while (!((line = dataInputStream.readUTF()).equals("EOF"))) {
content= content +line;//System.out.println(line);
}
}catch(Exception e) {
e.printStackTrace();
}
System.out.println("收到:" +content);
}
}
}.start();
Scanner scanner= newScanner(System.in);
String message;while (true) {
message=scanner.nextLine();if (message.equals("#qiut")) break;
dataOutputStream.writeUTF(message);
dataOutputStream.writeUTF("EOF");
dataOutputStream.flush();
}
dataInputStream.close();
dataOutputStream.close();
s.close();
}
}
聊天程序的流程图如下:
但是,光会用JAVA编写聊天程序显然是不行的,让我们深入其API探讨一下socket的建立过程。
在程序中,客户端初始化了一个socket连接,用来连接服务器,
调试进入之后,调用的是如下构造方法
上图中的构造方法在参数处理之后,调用了自身的其他构造,其中,下图的构造方法中,address为服务器端口地址,localAddr为自身端口地址,stream为是否要打开传输流。
在构造函数中,首先调用的是setImpl( )方法,调试跟踪发现,impl采用的是
Impl=new SocksSocketimpl()构造的,impl是SocketImpl类型,实现了SocketOptions接口,用来描述socket的参数。
再往下,看看SocksSocketImpl是如何构造的。
SocksSocketImpl构造函数为空方法,但是他继承了PlainSocketImpl类,在看看PlainSocketimpl类的构造方法,其中构造了DualStackPlainSocketImpl对象,DualStackPlainSocketImpl对象表示双向栈的Socket对象,为带有双向流socket.
DualStackPlainSocketImpl构造函数如下:
在看完了setImpl()函数调用的,过程之后,继续往下走,在Socket函数中,接下来调用了createImpl()方法,方法里面调用了create()方法。
在那之后,在try catch块中调用了DualStackPlainSocketImpl对象的bind和Conect方法,DualStackPlainSocketImpl对象中的的bind和Conect方法,调用的是本地的方法库,调用的是C中的bind和connect方法,C语言中的bind方法和connect方法在Java API中就不在深究了。