通信常见问题小结

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();
}
//客户端发送"<m><type>end</type></m>"则结束
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("</m>")){
sbf.append((char)read);
s = sbf.toString();
if(!s.endsWith("</m>"))
read = ins.read();
}
System.out.println("读到的输入是:"+s);
char[] ch = s.toCharArray();
byte []b = new byte[ch.length];
for(int i=0;i<ch.length;i++){
b[i] = (byte)ch[i];
}
s = new String(b);
return s;

}catch(IOException ef){
// ef.printStackTrace();
//当有特殊情况客户端断开,因为在协议中以定义结束时发送type=end;
return "<m><type>end</type></m>";
}
}

(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("</m>")){
sbf.append((char)read);
s = sbf.toString();
if(!s.endsWith("</m>"))
read = ins.read();
}
System.out.println("读到的输入是:"+s);
char[] ch = s.toCharArray();
byte []b = new byte[ch.length];
for(int i=0;i<ch.length;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()来读取客户机或服务器发送来的文件数据。

7. 中文字符串乱码:参见另一篇博文。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值