5.关闭打开的流。
下面是RemoteFileClient 的代码清单
import java.io.*; import java.net.*;
public class RemoteFileClient { protected BufferedReader socketReader; protected PrintWriter socketWriter; protected String hostIp; protected int hostPort;
public RemoteFileClient(String aHostIp, int aHostPort) { hostIp = aHostIp; hostPort = aHostPort; } public String getFile(String fileNameToGet) { StringBuffer fileLines = new StringBuffer();
try { socketWriter.println(fileNameToGet); socketWriter.flush();
String line = null; while ((line = socketReader.readLine()) != null) fileLines.append(line + "/n"); } catch (IOException e) { System.out.println("Error reading from file&: " + fileNameToGet); }
return fileLines.toString(); } public static void main(String[] args) { RemoteFileClient remoteFileClient = new RemoteFileClient("127.0.0.1", 3000); remoteFileClient.setUpConnection(); String fileContents = remoteFileClient.getFile("RemoteFile.txt"); remoteFileClient.tearDownConnection();
System.out.println(fileContents); } public void setUpConnection() { try { Socket client = new Socket(hostIp, hostPort);
OutputStream outToServerStream=client.getOutputStream(); InputStream inFromServerStream=client.getInputStream(); socketReader = new BufferedReader(new InputStreamReader(inFromServerStream)); socketWriter = new PrintWriter(outToServerStream);
} catch (UnknownHostException e) { System.out.println("Error setting up socket connection: unknown host at " + hostIp + ":" + hostPort); } catch (IOException e) { System.out.println("Error setting up socket connection: " + e); } } public void tearDownConnection() { try { socketWriter.close(); socketReader.close(); } catch (IOException e) { System.out.println("Error tearing down socket connection: " + e); } } } |
好了,现在来看服务器端的程序怎么写.
创建RemoteClientServer类:
import java.io.*; import java.net.*;
public class RemoteFileServer { protected int listenPort = 3000; public static void main(String[] args) { } public void acceptConnections() { } public void handleConnection(Socket incomingConnection) { } } |
跟客户机中一样,首先导入 java.net 的 java.io。接着,给我们的类一个实例变量以保存端口,我们从该端口侦听进入的连接。缺省情况下,端口是 3000。
acceptConnections()将允许客户机连接到服务器 handleConnection()负责与客户机 Socket 交互以将您所请求的文件的内容发送到客户机。
首先看main()
public static void main(String[] args) { RemoteFileServer server = new RemoteFileServer(); server.acceptConnections(); } |
非常简单,因为主函数无非是让服务器进入监听状态,所以直接调用acceptConnection().需要注意的是,必须先创建RemoteFileServer()的实例,而不是直接调用.
那么服务器是怎样通过acceptConnection()来监听客户机的连接呢?并且如果兼听到了,又怎样处理呢?我们来看
public void acceptConnections() { try { ServerSocket server = new ServerSocket(listenPort);//同客户机的Socket对应,在服务器端,我们需要ServerSocket对象,参数是兼听的端口号 Socket incomingConnection = null;//创建一个客户端的Socket变量,以接收从客户端监听到的Socket while (true) { incomingConnection = server.accept();//调用该 ServerSocket 的 accept() 来告诉它开始侦听, handleConnection(incomingConnection); } file&://不/断监听直到来了一个连接请求,然后交由handleConnection处理 } catch (BindException e) { System.out.println("Unable to bind to port " + listenPort); } catch (IOException e) { System.out.println("Unable to instantiate a ServerSocket on port: " + listenPort); } } |
无论何时如果创建了一个无法绑定到指定端口(可能是因为别的什么控制了该端口)的 ServerSocket,Java 代码都将抛出一个错误。所以这里我们必须捕捉可能的 BindException。同时,与在客户机端上时一样,我们必须捕捉 IOException,当我们试图在 ServerSocket 上接受连接时,它就会被抛出。可以通过用毫秒数调用 setSoTimeout() 来为 accept() 调用设置超时,以避免实际长时间的等待。调用 setSoTimeout() 将使 accept() 经过指定占用时间后抛出 IOException
最关键的处理在handleConnection()中,这时已经连接到了客户端的Socket,要从该Socket中读取客户端的请求并且响应。
public void handleConnection(Socket incomingConnection) { try { OutputStream outputToSocket = incomingConnection.getOutputStream(); InputStream inputFromSocket = incomingConnection.getInputStream();
file&://首/先获取同Socket相关联的流outputToSocket和InputStream file&://其/中outputToSocket是要返回给客户端Socket的流 file&://InputStream/是客户端发来的请求,在这里就是文件路径,即"RemoteFile.txt"
BufferedReader streamReader = new BufferedReader(new InputStreamReader(inputFromSocket));
file&://首/先要将InputStream转换到BufferedReader中
FileReader fileReader = new FileReader(new File(streamReader.readLine())); file&://从/BufferedReader中读出文件路径,建立新对象FileReader
BufferedReader bufferedFileReader = new BufferedReader(fileReader);
file&://再/次建立BufferedReader对象,这一次它读取得是文件里面的内容
PrintWriter streamWriter = new PrintWriter(OutputStream);
file&://把/Socket的outputToSocket流包装进PrintWriter 以使我们能够发送文件信息到客户端
String line = null; while ((line = bufferedFileReader.readLine()) != null) { streamWriter.println(line); } file&://从/bufferedFileReader中读出文件信息,再经由streamWriter输出到客户端
fileReader.close(); streamWriter.close();//注意Socket的两个流关闭的顺序 streamReader.close(); file&://完/成之后关闭所有流
} catch (Exception e) { System.out.println("Error handling a client: " + e); } } |
请注意完成所有操作之后关闭流的顺序,streamWriter的关闭在streamReader的关闭之前。这不是偶然的,假如将关闭次序颠倒过来,客户端将不会获取到任何文件信息,你可以调试一下看看.这是为什么呢?原因是如果你在关闭 streamWriter 之前关闭 streamReader,则你可以以往 streamWriter中写任何东西,但没有任何数据可以通过通道(通道被关闭了).但奇怪的是,我不是已经在之前的streamWriter.println()中输出了吗?难道非要等到所有的流关闭之后输出到客户端的信息的东西才能到达?我试着将
streamWriter.close(); streamReader.close();
屏蔽掉,看是否依然能够实现正常的通信,结果发现不行,程序死机.可能是因为通道没有闭合导致的.那么至少可以说明,只有将通道按某种顺序正常关闭,才能完成通讯数据的传输,否则客户端收不到信息.
最后依然是总结一下创建服务器端程序的步骤
1.用一个你想让它侦听传入客户机连接的端口(比如程序中的3000)来实例化一个 ServerSocket(如有问题则抛出 Exception)。
2.循环调用ServerSocket的accept()以监听连接
3.获取客户端的Socket流以进行读写操作
4.包装流
5.对客户端的Socket进行读写
6.关闭打开的流(切记,永远不要在关闭 Writer 之前关闭 Reader),完成通信
下面是
RemoteFileServer 的代码清单
import java.io.*; import java.net.*;
public class RemoteFileServer { int listenPort; public RemoteFileServer(int aListenPort) { listenPort = aListenPort; } public void acceptConnections() { try { ServerSocket server = new ServerSocket(listenPort); Socket incomingConnection = null; while (true) { incomingConnection = server.accept(); handleConnection(incomingConnection); } } catch (BindException e) { System.out.println("Unable to bind to port " + listenPort); } catch (IOException e) { System.out.println("Unable to instantiate a ServerSocket on port: " + listenPort); } } public void handleConnection(Socket incomingConnection) { try { OutputStream outputToSocket = incomingConnection.getOutputStream(); InputStream inputFromSocket = incomingConnection.getInputStream();
BufferedReader streamReader = new BufferedReader(new InputStreamReader(inputFromSocket));
FileReader fileReader = new FileReader(new File(streamReader.readLine()));
BufferedReader bufferedFileReader = new BufferedReader(fileReader); PrintWriter streamWriter = new PrintWriter(outputToSocket); String line = null; while ((line = bufferedFileReader.readLine()) != null) { streamWriter.println(line); }
fileReader.close(); streamWriter.close(); streamReader.close(); } catch (Exception e) { System.out.println("Error handling a client: " + e); } } public static void main(String[] args) { RemoteFileServer server = new RemoteFileServer(3000); server.acceptConnections(); } }
|
|
|