Java通信程序需要注意的问题:
1. 创建服务器:
指定的端口号port已被占用,或端口号超过一个int型的范围,都会抛出一个异常;
2. 方法阻塞问题:
(1) 服务器对象在调用accept()方法处会阻塞,直到等到有客户机连接进入
(2) 套接字对象在用输入流读取字节时,会阻塞在read()方法处,直到读到客户机输入的字节;
3. 为什么需要用多线程Thread:
不论是服务器的连接对象或者是客户机的连接对象,在通信过程中,他们都要死循环的用自己的输入流来读取对方发来的字节,而且要不断的向对方发送数据,由于在顺序结构中是不可能同时进行这两个行为的调用,因此需要启动一个线程。
4. throws与try……catch
在通信程序中,会遇到很多很多的异常情况,对于会抛出异常的方法来说,究竟是该将异常抛给上级即throws还是应该使用try……catch来对异常进行处理,这里面有很多的讲究,但并无一个确定的套路,完全掌握于程序员自己的手中。例如:当客户机主动关闭程序时,服务器端在读取客户机发送来的字节的方法中一定会抛出异常,这时如果throws则会由上级语句进行try……catch,关闭套接字连接;如果是try……catch,则需要在catch语句中返回一个客户机主动断开的消息,
(1)采用 try……catch的处理机制:
public void run(){
String meg = readMessage();
while(!MessageTool.getType(meg).equals("end")){
processMeg(meg);
//读取消息
meg = readMessage();
}
//客户端发送"
end"则结束
try{
setEndMessage();
System.out.println("客户端主动断开!!!");
client.close();
}catch(IOException ef){
// ef.printStackTrace();
}
//向所有用户发送下线消息
sendDownLineMessage(this.user.getName());
ClientManage.removeClient(this);
}
/**
* 读取客户端发来的消息
* @return
*/
public String readMessage(){
try{
int read = ins.read();
String s="";
StringBuffer sbf = new StringBuffer();
//客户端没有断开就一直读取
while(!s.endsWith("")){
sbf.append((char)read);
s = sbf.toString();
if(!s.endsWith(""))
read = ins.read();
}
System.out.println("读到的输入是:"+s);
char[] ch = s.toCharArray();
byte []b = new byte[ch.length];
for(int i=0;i
b[i] = (byte)ch[i];
}
s = new String(b);
return s;
}catch(IOException ef){
// ef.printStackTrace();
//当有特殊情况客户端断开,因为在协议中以定义结束时发送type=end;
return "
end";
}
}
(2)采用throws的处理机制:
public void run(){
String meg = readMessage();
try{
while(!MessageTool.getType(meg).equals("end")){
processMeg(meg);
//读取消息
meg = readMessage();
}
}catch(IOException ef){
//跳出循环
break;
}
//关闭客户端
System.out.println("客户端主动断开!!!");
client.close();
//向所有用户发送下线消息
sendDownLineMessage(this.user.getName());
ClientManage.removeClient(this);
}
/**
* 读取客户端发来的消息
* @return
*/
public String readMessage()throws IOException {
int read = ins.read();
String s="";
StringBuffer sbf = new StringBuffer();
//客户端没有断开就一直读取
while(!s.endsWith("")){
sbf.append((char)read);
s = sbf.toString();
if(!s.endsWith(""))
read = ins.read();
}
System.out.println("读到的输入是:"+s);
char[] ch = s.toCharArray();
byte []b = new byte[ch.length];
for(int i=0;i
b[i] = (byte)ch[i];
}
s = new String(b);
return s;
}
5. 客户机或者服务器在循环读取流中的字节时,会遇到try……catch与while循环的共同使用的情况,这时应该将while放在try语句块之内来处理,因为对于一个客户机来说,就是一个流,只需要一次try……catch就可以处理流中的错误了。
6. 流的小细节:
在输出流输出数据结束时,要注意用outputstream.flush();在输入流读取数据时,由于read()是将一个一个字节读取到数组中而readFully()则是一次性读取所有的字节,不容易造成数据的丢失,因此,在读取大文件时用readFully()效果较好;在流结束时,要用close()方法关闭流。因此,在QQ传送文件时,常常采用readFully()来读取客户机或服务器发送来的文件数据。
原文转自:
http://dqldqldql110-sina-com.iteye.com/blog/975707
阅读(2401) | 评论(0) | 转发(1) |