面是本次学习的笔记。主要分异常类型、交互原理、Socket、ServerSocket、多线程这几个方面阐述。
异常类型 在了解 Socket 的内容之前,先要了解一下涉及到的一些异常类型。以下四种类型都是继承于 IOException,所以很多之后直接弹出 IOException 即可。 UnkownHostException: 主机名字或 IP 错误 ConnectException: 服务器拒绝连接、服务器没有启动、(超出队列数,拒绝连接) SocketTimeoutException: 连接超时 BindException: Socket 对象无法与制定的本地 IP 地址或端口绑定 交互过程 Socket 与 ServerSocket 的交互,下面的图片我觉得已经说的很详细很清楚了。 在上面的图中,Client 一方在建立 socket 以后,则调用 socket.connect(server IP, server port) 去主动请求建立与 server 通信的连接。Socket 构造函数Socket()
Socket(InetAddress address, int port)throws UnknownHostException, IOExceptionSocket(InetAddress address, int port, InetAddress localAddress, int localPort)throws IOException Socket(String host, int port)throws UnknownHostException, IOException Socket(String host, int port, InetAddress localAddress, int localPort)throws IOException 除去第一种不带参数的之外,其它构造函数会尝试建立与服务器的连接。如果失败会抛出 IOException 错误。如果成功,则返回 Socket 对象。InetAddress 是一个用于记录主机的类,其静态 getHostByName(String msg) 可以返回一个实例,其静态方法 getLocalHost() 也可以获得当前主机的 IP 地址,并返回一个实例。Socket(String host, int port, InetAddress localAddress, int localPort) 构造函数的参数分别为目标 IP、目标端口、绑定本地 IP、绑定本地端口。Socket 方法 getInetAddress(); 远程服务端的 IP 地址 getPort(); 远程服务端的端口 getLocalAddress() 本地客户端的 IP 地址 getLocalPort() 本地客户端的端口 getInputStream(); 获得输入流 getOutStream(); 获得输出流值得注意的是,在这些方法里面,最重要的就是 getInputStream() 和 getOutputStream() 了。Socket 状态 isClosed(); // 连接是否已关闭,若关闭,返回 true;否则返回 falseisConnect();// 如果曾经连接过,返回 true;否则返回 falseisBound(); // 如果 Socket 已经与本地一个端口绑定,返回 true;否则返回 false 如果要确认 Socket 的状态是否处于连接中,下面语句是很好的判断方式。半关闭 Socket 很多时候,我们并不知道在获得的输入流里面到底读多长才结束。下面是一些比较普遍的方法:
- boolean isConnection = socket.isConnected() && !socket.isClosed(); //判断当前是否处于连接
- public void service() {
- while (true) {
- Socket socket = null;
- try {
- socket = serverSocket.accept(); //从连接队列中取出一个连接,如果没有则等待
- System.out.println("新增连接:" + socket.getInetAddress() + ":" + socket.getPort());... //接收和发送数据
- } catch(IOException e) {
- e.printStackTrace();
- } finally {
- try {
- if (socket != null) socket.close(); //与一个客户端通信结束后,要关闭Socket
- } catch(IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- public void service(){
- while(true){
- Socket socket=null;
- try{
- socket=serverSocket.accept(); //主线程获取客户端连接
- Thread workThread=new Thread(new Handler(socket)); //创建线程
- workThread.start(); //启动线程
- }catch(Exception e){
- e.printStackTrace();
- }
- }
- }
- class Handler implements Runnable {
- private Socket socket;
- public Handler(Socket socket) {
- this.socket = socket;
- }
- public void run() {
- try {
- System.out.println("新连接:" + socket.getInetAddress() + ":" + socket.getPort());
- Thread.sleep(10000);
- } catch(Exception e) {
- e.printStackTrace();
- } finally {
- try {
- System.out.println("关闭连接:" + socket.getInetAddress() + ":" + socket.getPort());
- if (socket != null) socket.close();
- } catch(IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
当然是先多线程还有其它的方式,譬如线程池,或者 JVM 自带的线程池都可以
来源: