分享
 
 
 

菜鸟初学Java的备忘录(五)

王朝java/jsp·作者佚名  2008-05-31
窄屏简体版  字體: |||超大  

对几个Java的基础知识作一下补充。

一.异常

Java对异常的处理同Delphi一样,不是刻意的去避免它的发生,而是等它发生后去补救.

Delphi的异常处理简单来说就是一下语句

Try

Except//异常发生后就转入此处执行

Finally//不管异常发不发生,都转入此处运行

End

与此相类似,Java的异常处理的基本形式如下

try{

}catch(ExceptionType1 e){

file://对异常情况1的处理

}catch(ExceptionType2 e){

file://对异常情况2的处理

throw(e)//抛出异常,和Delphi中的raise是一回事

}

要补充的是,对大多数的异常,假如你要在正常运行的程序中而不是捕捉异常的程序中明确的抛出,Java的编译器需要你事先对你要抛出的异常作声明,否则不答应编译通过.这个任务是由throws来完成的.

二.Java的输入输出流

2.1 输出

System.out.print file://这里out是一个静态方法哦

System.out.println

System.err.print file://err和out一样也是标准输出,至于有什么不同,我目前还不清楚

System.err.println

2.2 输入

System.in.read()

2.3 文件的操作

只需要几个带注释的例子就可以了。

第一个是一个显示文件基本信息的程序

import java.io.*;//调入和io相关的类

class fileinfo{

file://注重,main函数一定是静态方法

public static void main(String args[])throws IOException{

File fileToCheck;//使用文件对象创建实例

if (args.length>0){

for (int i=0;i<args.length;i++){

fileToCheck=new File(args[i]);//为文件对象分配空间

info(fileToCheck);//这里引用的info一定要是静态方法成员

}

}

else{

System.out.println("no file given");

}

}

public static void info(File f)throws IOException{

System.out.println("Name:"+f.getName());

System.out.println("Path:"+f.getPath());

if (f.exists()){

System.out.println("File exists.");

System.out.print((f.canRead()?" and is Readable":""));//判定函数,假如满足条件,输出前者,否则输出后者

System.out.print((f.canWrite()?"and is Writable":""));

System.out.print(".");

System.out.println("File is"+f.length()+"bytes.");

}

else{

System.out.println("File does not exist.");

}

}

}

第二个例子是一个存储电话信息的小程序,用户输入姓名和电话号码,程序将其存入phone.numbers文件中,通过FileOutputStream来实现

import java.io.*;

class phones{

static FileOutputStream fos;

public static final int lineLength=81;

public static void main(String args[])throws IOException{

byte[] phone=new byte[lineLength];

byte[] name=new byte[lineLength];

int i;

fos=new FileOutputStream("phone.numbers");

while(true){

System.err.println("Enter a name(enter ′done′ to quit)");

readLine(name);

if ("done".equalsIgnoreCase(new String(name,0,0,4))){

break;

}

System.err.println("Enter the phone number");

readLine(phone);

for (i=0;phone[i]!=0;i++){

fos.write(phone[i]);

}

fos.write(′,′);

for (i=0;name[i]!=0;i++){

fos.write(name[i]);

}

fos.write(′ ′);

}

fos.close();

}

private static void readLine(byte line[])throws IOException{

int i=0,b=0;

while((i<(lineLength-1))&&((b=System.in.read())!=′ ′)){

line[i++]=(byte)b;

}

line[i]=(byte)(0);

}

}

2.4 流

无非是两种

输出流,让我们来写的

输入流,给我们来读的

java.io包中有很多种类的输入输出流

1.FileInputStream和FileOutputStream 节点流

2.BufferedInputStream和BufferedOutputStream 过滤流

3.DataInputStream和DataOutputStream 增强的过滤流

4.PipedInputStream和PipledOutputStream 用于线程的流

把握了流的概念,就可以开始Sockets的学习了.关于Socket的作用,昨天我已经讲了.

现在,我们将创建一个简单的通讯程序,以获得对Socket的实质性的熟悉.该程序包括两个部分,客户机(RemoteFileClient)和服务器(RemoteFileServer).客户机向服务器发出请求,要求读取服务器上的文件信息.服务器将响应请求,将相应的文件信息传给客户机,将相应的文件信息传给客户机.

首先我们创建RemoteFileClient类:

import java.io.*;//java.io 包提供对流进行读写的工具,也是与 TCP 套接字通信的唯一途径

import java.net.*;//java.net 包提供套接字工具。

public class RemoteFileClient {

protected String hostIp;

protected int hostPort;

protected BufferedReader socketReader;//负责读数据的对象

protected PrintWriter socketWriter;//负责写数据的对象

file://类的构造器有两个参数:远程主机的 IP 地址(hostIp)和端口号(hostPort)各一个.构造器将它们赋给实例变量

public RemoteFileClient(String aHostIp, int aHostPort) {

hostIp = aHostIp;

hostPort = aHostPort;

}

public static void main(String[] args) {

}

file://连接到远程服务器

public void setUpConnection() {

}

file://向远程服务器请求文件信息

public String getFile(String fileNameToGet) {

}

file://从远程服务器上断开

public void tearDownConnection() {

}

}

首先来实现main()

public static void main(String[] args) {

RemoteFileClient remoteFileClient = new RemoteFileClient("127.0.0.1", 3000);//为了方便调试,我们把本地服务器当作远程服务器

remoteFileClient.setUpConnection();//连接。不能直接使用setUpConnection,因为它是非静态变量,需要创建实例后,对实例进行引用,可以看我第一天的日记,上面写的非常具体

String fileContents =

remoteFileClient.getFile("RemoteFile.txt");//读取

remoteFileClient.tearDownConnection();//断开

System.out.println(fileContents);//输出读取内容

}

步骤非常清楚.那么我们分别看连接,读取,断开是怎么实现的

1.连接

public void setUpConnection() {

try {

Socket client = new Socket(hostIp, hostPort);//创建Socket对象

OutputStream outToServerStream=client.getOutputStream();

InputStream inFromServerStream=client.getInputStream();

socketReader = new BufferedReader(new InputStreamReader(inFromServerStream));

file://把Socket的InputStream包装进BufferedReader 以使我们能够读取流的行

socketWriter = new PrintWriter(outToServerStream);

file://把Socket的OutputStream包装进PrintWriter 以使我们能够发送文件请求到服务器

} catch (UnknownHostException e) {

System.out.println("Error setting up socket connection: unknown host at " + hostIp + ":" + hostPort);

file://对Socket对象创建错误的异常处理

} catch (IOException e) {

System.out.println("Error setting up socket connection: " + e);

file://对IO错误的异常处理

}

}

2.读取

public String getFile(String fileNameToGet) {

StringBuffer fileLines = new StringBuffer();//StringBuffer对象也是String对象,但是比它更灵活,这里是用来存放读取内容的

try {

socketWriter.println(fileNameToGet);

socketWriter.flush();//文件存放地址输出到socketWriter中,然后清空缓冲区,让这个地址送到服务器中去

String line = null;

while ((line = socketReader.readLine()) != null)

fileLines.append(line + " ");

file://既然已经发送到服务器去了,那我们都要等待响应,这里的程序就是等待服务器把我们所需要的文件内容传过来

} catch (IOException e) {

System.out.println("Error reading from file: " + fileNameToGet);

}

return fileLines.toString();//别忘了把buffer中的内容转成String再返回

}

3.断开

public void tearDownConnection() {

try {

socketWriter.close();

socketReader.close();

} catch (IOException e) {

System.out.println("Error tearing down socket connection: " + e);

}

}

tearDownConnection() 方法只别关闭我们在 Socket 的 InputStream 和 OutputStream 上创建的 BufferedReader 和 PrintWriter。这样做会关闭我们从 Socket 获取的底层流,所以我们必须捕捉可能的 IOException

好,现在可以总结一下客户机程序的创建步骤了

1.用要连接的机器的IP端口号实例化Socket(如有问题则抛出 Exception)。

2.获取 Socket 上的流以进行读写.

3.把流包装进 BufferedReader/PrintWriter 的实例.

4.对 Socket 进行读写.具体说来,就是在Writer上传送文件地址信息给服务器,在Reader上读取服务器传来的文件信息

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 + " ");

} 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();

}

}

好了,Socket总算是入门了

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有