2.1接收和关闭与客户端的连接
ServeSocket的accept()方法从连接请求队列中取出一个与客户端的连接,然后创建于客户端连接Socket对象,并将它返回。如果队列中没有连接请求,accept()方法就一直等待
,直到接收到连接请求才返回。
接下来,服务器从Socket对象中获得输入流和输出流,就能与客户交互数据。当服务器正在进行发送数据的操作时,如果客户端断开了连接,那么服务器就会抛出IOException的之类异常SocketException异常:java.net.SocketException:Connection reset by peer
这只是服务器与单个客户通信中出现的异常,这种异常应该被捕获,使得服务器能继续与其他客户通信。
一下代码采用了单线程服务器采用的通信流程:
public void serve()
{
while(true)
{
Socket socket=null;
try{
socket=serveSocket.accept();
System.out.println("new connection accept:"+socket.getInetAddress()
+":"+socket.getPort());
//接收和发送数据
}catch(Exception e){
e.printStackTrace();
}finally{
try{
if(socket!=null)
socket.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
与单个客户通信的代码放在一个try代码块中,如果遇到异常,该异常被catch代码块捕获
try代码块后面还有一个finally代码块,它保证不管与客户端通信正常结束还是异常结束,最后都会关闭Socket,断开与这个客户的连接
2.2关闭ServeSocket
ServeSocket 的close()方法使服务器释放被占用的端口,并且断开与所有客户的连接。当一个服务器程序运行结束时,即使没有执行ServeSocket的close()方法,操作系统也会释放这个服务器占用的端口,因此,服务器程序并不一定要在结束之前执行ServeSocket的close()方法。
在某些情况下,如果希望直接释放服务器端口,以便让其他程序占用该端口,则可以显示调用ServeSocket的close()方法。例如一下代码用于扫描1--65535之间的端口号,如果ServeSocket成功创建,意味着该端口未被其他服务器进程绑定,否则说明该端口已经被其他进程占用:
for(int port=1;port<=65535;port++)
{
try{
ServeSockt serveSocket=new ServeSocket(port);
serveSocket.close();
}catch(IOException e){
System.out.println("端口"+port+"已经被其他服务器进程占用");
}
}
ServeSockt 对象后,就马上关闭它,以便及时释放它占用的端口,从而避免程序临时占用系统的大多数端口。
ServeSockt 的isClose()端口方法判断ServeSockt 是否与一个端口绑定,只要ServeSockt 与一个端口绑定,即使它已经关闭,isBind()方法也会返回true。如果需要确定一个ServeSockt 已经与特定端口绑定,并且还没有被关闭,则可以采用以下方式:
boolean isOpen=serveSocket.isBind()&&serveSocket.isClose();
2.3获取ServeSocket的信息
ServeSocket的以下两个get方法可分别获得服务器绑定的IP地址,以及绑定的端口:
~public InetAddress getInetAddress ();
~public int getLocalPort();
前面已经讲到,在构造ServeSocket时,如果把端口设置为0,那么由操作系统为服务器分配一个端口(称为匿名端口),程序只要调用getLocalPort()方法就能获知这个端口号,一下程序可以验证
package com.sxt.socket.sersocket;
import java.io.IOException;
import java.net.ServerSocket;/**
* @author jt
*2015-12-4 下午9:28:04
*
*/
public class RandomPort { /**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
ServerSocket serveSocket=new ServerSocket();
System.out.println("监听的端口号为:"+serveSocket.getLocalPort());
}}
多数程序会监听固定端口,这样便于客户程序访问服务器,匿名端口一般适用于服务器与客户进程之间的临时通信,通信结束,就断开连接,并且ServeSocket占用的临时端口也会释放。
FTP之间(文件传输协议)就使用了匿名端口
FTP使用两个并行的TCP连接:一个是控制连接,一个数数据连接。控制连接用于在客户和服务器之间发送控制信息,如用户名和口令,改变远程目录的命令或则上传和下载的命令。数据连接用于传送文件。TCP服务器在21端口上监听控制连接,如果客户要求上传和下载文件,就另外建立一个数据连接,通过它来传送数据。数据连接的建立有两种连接方式:
(1)如下图,TCP服务器在20端口上监听数据连接,TCP客户主动请求建立与该端口的连接。
(2)如下图,首先TCP客户创建一个监听匿名端口的ServerSocket,在把这个ServerSocket监听的端口号(调用ServerSocket的getLocalport()方法就能得到端口号)发送给TCP服务器。然后由TCP服务器主动请求建立与客户端的连接
以上第二种方式就是使用了匿名端口,并且是在客户端使用的,用于和服务器建立临时的连接。在实际应用中,在服务器端也可以使用匿名端口。