[Java]详解Socket和ServerSocket学习笔记
对于即时类应用或者即时类的游戏,HTTP协议很多时候无法满足于我们的需求。这会,Socket对于我们来说就非常实用了。下面是本次学习的笔记。主要分异常类型、交互原理、Socket、ServerSocket、多线程这几个方面阐述。 异常类型 在了解Socket的内容之前,先要了解一下涉及到的一些异常类型。以下四种类型都是继承于IOException,所以很多之后直接弹出IOException即可。 UnkownHostException: 主机名字或IP错误 ConnectException: 服务器拒绝连接、服务器没有启动、(超出队列数,拒绝连接) SocketTimeoutException: 连接超时 BindException: Socket对象无法与制定的本地IP地址或端口绑定 交互过程 Socket与ServerSocket的交互,下面的图片我觉得已经说的很详细很清楚了。 Socket 构造函数 Socket() Socket(InetAddress address,int port)throws UnknownHostException,IOException Socket(InetAddress address,int port,InetAddress localAddress,int localPort)throws IOException Socket(String host,IOException Socket(String host,int localPort)throws IOException 除去第一种不带参数的之外,其它构造函数会尝试建立与服务器的连接。如果失败会抛出IOException错误。如果成功,则返回Socket对象。 InetAddress是一个用于记录主机的类,其静态getHostByName(String msg)可以返回一个实例,其静态方法getLocalHost()也可以获得当前主机的IP地址,并返回一个实例。Socket(String host,int localPort)构造函数的参数分别为目标IP、目标端口、绑定本地IP、绑定本地端口。 Socket方法 getInetAddress(); 远程服务端的IP地址 getPort(); 远程服务端的端口 getLocalAddress() 本地客户端的IP地址 getLocalPort() 本地客户端的端口 getInputStream(); 获得输入流 getOutStream(); 获得输出流 值得注意的是,在这些方法里面,最重要的就是getInputStream()和getOutputStream()了。 Socket状态 isClosed(); //连接是否已关闭,若关闭,返回true;否则返回false isConnect(); //如果曾经连接过,返回true;否则返回false isBound(); //如果Socket已经与本地一个端口绑定,返回true;否则返回false 如果要确认Socket的状态是否处于连接中,下面语句是很好的判断方式。 boolean isConnection=socket.isConnected() && !socket.isClosed(); //判断当前是否处于连接 半关闭Socket 很多时候,我们并不知道在获得的输入流里面到底读多长才结束。下面是一些比较普遍的方法:
ServerSocket 构造函数 ServerSocket()throws IOException ServerSocket(int port)throws IOException ServerSocket(int port,int backlog)throws IOException ServerSocket(int port,int backlog,InetAddress bindAddr)throws IOException 注意点: 1. port服务端要监听的端口;backlog客户端连接请求的队列长度;bindAddr服务端绑定IP 2. 如果端口被占用或者没有权限使用某些端口会抛出BindException错误。譬如1~1023的端口需要管理员才拥有权限绑定。 3. 如果设置端口为0,则系统会自动为其分配一个端口; 4. bindAddr用于绑定服务器IP,为什么会有这样的设置呢,譬如有些机器有多个网卡。 5. ServerSocket一旦绑定了监听端口,就无法更改。ServerSocket()可以实现在绑定端口前设置其他的参数。 单线程的ServerSocket例子 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();} } } } 多线程的ServerSocket 多线程的好处不用多说,而且大多数的场景都是多线程的,无论是我们的即时类游戏还是IM,多线程的需求都是必须的。下面说说实现方式:
实现多线程的方法要么继承Thread类,要么实现Runnable接口。当然也可以使用线程池,但实现的本质都是差不多的。 这里举例: 下面代码为服务器的主线程。为每个客户分配一个工作线程: 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(); } } } 当然这里的重点在于如何实现Handler这个类。Handler需要实现Runnable接口: 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自带的线程池都可以。这里就不说明了。 以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |