在线聊天系统雏形总结(续)
今天主要说说服务器端的设计:
总共有两个版本,版本一是很简单的,就是在main方法中起一个server socket,通过DataInputStream读取client的内容,但这个版本有一个很大的缺陷在于我的DataInputStream通的是一个阻塞式的方法readUTF(),并放在了一个死循环里,这样如果再起一个client,是打死连不上的,所以这个只能连上一个client,如果要连上多个,我们就采用第二个版本,采用了线程,主线程负责与client做连接,而子线程就是做自己想做的事情,想做什么就做什么,比如这个项目就是读入client端的字符。
版本一由于很简单,所以不打算多总结,但是有两个exception 不得不提一下。一个是BoundException,在文档的解释为“试图将套接字绑定到本地地址和端口时发生错误的情况下,抛出此异常。这些错误通常发生在端口正在使用中或无法分配所请求的本地地址时”我们在起一个server端的serverSocket时,有时发现原先已经起了一个,所以会报这个异常,这样我们就try-catch处理一下,记得不要看到exception就往外抛,能推测出原因的就用System.out.println()打印出来提示用户改如何操作,不能猜测出来的就至少写个printStackTrace();第二个异常是EOFException,这个原因是tomcat对硬盘的session读取失败,网上找到一个彻底的解决办法是:将work下面的文件清空,主要是*.ser文件,或者只是删除掉session.ser即可以解决。 不过和这个好像没什么关系,eof主要是找不到结束的标志,如果读取的方法是非block方式的就要在特别注意了,改换成block就好了。
版本二的思路在上面以作了个简单的介绍,在这个版本中我们包装了一个client类,这个主要用来处理client传过来的除连接上的请求,这个client类implements Runnable接口重写run方法,作为一个子线程的参数传进线程。在版本二中我们还实现了一个功能就是把一个client端发送出来的内容通过server端转发给其他的用户,这就要考虑用一个东西来存储所有其他的client了,我开始想到的也是数组,但是数组是固定大小的容器,到底会有多少client会连上来,谁也说不定,所以数组是不行的,还有链表容器和数组容器,在这里我们选用数组容器是最好的,因为用的最多的是遍历而不是查找,记得要使用范式。三种遍历方法:for(int i=0; i<clients.size(); i++) {
Client c = clients.get(i);
c.send(str);
}
/*
for(Iterator<Client> it = clients.iterator(); it.hasNext(); ) {
Client c = it.next();
c.send(str);
}
*/
/*
Iterator<Client> it = clients.iterator();
while(it.hasNext()) {
Client c = it.next();
c.send(str);
}
*/
线程的两种实现方式,一种是从thread类继承,还有一种是实现runnable接口,能实现接口的就不用继承,因为后者更灵活
总的体会还是要说的:那就是时刻要记住一句话就是:程序是调出来的。那么怎么调试程序呢?其实也就是按照人正常的思维去理清思路,逐步分析逻辑关系,找出哪里可能会出问题,然后一步步进行调试,要铭记没有解决不了的问题。还有每次解决完一个版本时就要问自己一个问题:“这样就OK了吗?”引发对问题的进一步思考。
今天先总结到这里吧,之后在做一个关于线程使用方面的总结。