编写 Java 聊天程序并探究Socket API
先上一张网络聊天程序运行图:
功能实现的很简单,客户端输入服务器IP和端口信息连接服务器,建立连接之后,客户端和服务器就可以进行双向通信了。
源码如下:
client端 源代码
import java.io.*; import java.net.Socket; import java.util.Scanner; public class Client extends Netutil implements Runnable{ String IPAdress; int port; Client(String IPAdress,int port){ this.IPAdress=IPAdress; this.port=port; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("请输入IP地址:"); String ip=scanner.nextLine(); System.out.print("请输入端口号:"); int port=scanner.nextInt(); Client client1=new Client(ip,port); Thread thread1=new Thread(client1); thread1.start(); } @Override public void run() { try { Socket s = new Socket(this.IPAdress, this.port); super.Oprate(s); } catch (IOException e) { e.printStackTrace(); } } }
Server端源代码:
import java.io.*; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; public class Server extends Netutil { public static void main(String[] args) { new Server().Get(); } /*进入的方法*/ public void Get() { 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(new Handler(accept)); hander.start(); } } catch (IOException e) { e.printStackTrace(); } } /** * 内部处理类 */ class Handler extends Netutil implements Runnable { Socket socket; public Handler(Socket socket) { this.socket = socket; } @Override public void run() { try { super.Oprate(socket); } catch (IOException e) { e.printStackTrace(); } } } }
聊天功能实现类:
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.util.Scanner; public class Netutil { public void Oprate(Socket s) throws IOException { DataInputStream dataInputStream = new DataInputStream(s.getInputStream()); DataOutputStream dataOutputStream = new DataOutputStream(s.getOutputStream()); new Thread() { @Override public void run() { 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 = new Scanner(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中就不在深究了。