觉得慢的原因主要是每个线程会去检查VECTOR中是否有自己的消息
直观的想法是这些线程接收信息都是被动的 而不应该主动去检查,不没有消息的时候会花费无谓的系统时间。你的想法有点像MEDIATOR PATTERN由一个中间的协调者去处理多个用户间的通信,有可能的做法是做一个共享对象,每个线程都向它发消息,而这个对象则负责转发。
直观的想法是这些线程接收信息都是被动的 而不应该主动去检查,不没有消息的时候会花费无谓的系统时间。你的想法有点像MEDIATOR PATTERN由一个中间的协调者去处理多个用户间的通信,有可能的做法是做一个共享对象,每个线程都向它发消息,而这个对象则负责转发。
解决方案 »
- org.apache.jasper.JasperException: Template /template/ajax/text.ftl not found
- 请问使用什么技术可以让系统支持多个服务器。
- ************HttpClient+dom4j 问题**************
- hibernate-4.2.3 @OneToOne 不能用了么?
- 如何安装j2eesdk?
- 超难度 stringbuffer 处理10万条记录
- 一个hibernate查询的问题!
- 如何把一个UNIX下C++开发的程序提供的服务封装为一个WEB SERVICE??
- 数据库中取出纪录为空时,返回到页面显示信息怎么实现,急!
- 求救关于服务查找的程序?邦我看看!谢谢
- 不会下载!!!
- resin2.1不能用jstl???
public class SocketThread extends Thread implements java.util.Observer
{
private java.util.Observable observable = null;
public SocketThread(java.util.Observable observable)
{
this.observable = observable;
}
public void run()
{
observable.addObserver(this);
......
observable.deleteObserver(this);
}
......
public void update(Observable observable, Object msg)
{
....发送消息
}
接受到信息,则observable.notifyAll(msg);
}
而在主线程中
public class ServerObservable extends java.util.Observable
{
public void notifyAll(Object o)
{
....如果信息是发送给某个人的,查找出那个人的Thread,然后调用thread.update(this, o)
....如果信息发送给所有人,则
setChanged();
notifyObservers(o);
clearChanged();
}
}
对于接受到的消息的处理,可以采用ChainOfResponsibility模式,
可根据消息的类型分层处理,好处是一旦有新的消息类型加入的话,
只需增加一条消息处理链而无需对已有的类进行重新组织
// Client that tests the MultiJabberServer
// by starting up multiple clients.
import java.net.*;
import java.io.*;
class JabberClientThread extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
private static int counter = 0;
private int id = counter++;
private static int threadcount = 0;
public static int threadCount() {
return threadcount;
}
public JabberClientThread(InetAddress addr) {
System.out.println("Making client " + id);
threadcount++;
try {
socket =new Socket(addr, 8080);
} catch(IOException e) {
System.err.println("Socket failed");
// If the creation of the socket fails,
// nothing needs to be cleaned up.
}
try {
in =new BufferedReader(new InputStreamReader(socket.getInputStream()));
// Enable auto-flush:
out =new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
start();
} catch(IOException e) {
// The socket should be closed on any
// failures other than the socket
// constructor:
try {
socket.close();
} catch(IOException e2) {
System.err.println("Socket not closed");
}
}
// Otherwise the socket will be closed by
// the run() method of the thread.
}
public void run() {
try {
for(int i = 0; i < 25; i++) {
out.println("Client " + id + ": " + i);
String str = in.readLine();
System.out.println(str);
}
out.println("END");
} catch(IOException e) {
System.err.println("IO Exception");
} finally {
// Always close it:
try {
socket.close();
} catch(IOException e) {
System.err.println("Socket not closed");
}
threadcount--; // Ending this thread
}
}
}public class MultiJabberClient {
static final int MAX_THREADS = 40;
public static void main(String[] args)throws IOException, InterruptedException {
InetAddress addr =InetAddress.getByName(null);
while(true) {
if(JabberClientThread.threadCount()< MAX_THREADS)
new JabberClientThread(addr);
Thread.currentThread().sleep(100);
}
}
} ///:~
// A server that uses multithreading
// to handle any number of clients.
import java.io.*;
import java.net.*;
class ServeOneJabber extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public ServeOneJabber(Socket s) throws IOException {//Socket s这一句是关键,说明socket随着线程的建立而建立
socket = s;
in =new BufferedReader(new InputStreamReader(socket.getInputStream()));
// Enable auto-flush:
out =new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
// If any of the above calls throw an
// exception, the caller is responsible for
// closing the socket. Otherwise the thread
// will close it.
start(); // Calls run()
}
public void run() {
try {
while (true) {
String str = in.readLine();
if (str.equals("END")) break;
System.out.println("Echoing: " + str);
out.println(str);
}
System.out.println("closing...");
} catch(IOException e) {
System.err.println("IO Exception");
} finally {
try {
socket.close();
} catch(IOException e) {
System.err.println("Socket not closed");
}
}
}
}
public class MultiJabberServer {
static final int PORT = 8080;
public static void main(String[] args) throws IOException {
ServerSocket s = new ServerSocket(PORT);//serversockt只要一个,其他的连接都是用的socket
System.out.println("Server Started");
try {
while(true) {
// Blocks until a connection occurs:
Socket socket = s.accept();
try {
new ServeOneJabber(socket);
} catch(IOException e) {
// If it fails, close the socket,
// otherwise the thread will close it:
socket.close();
}
}
} finally {
s.close();
}
}
} ///:~
一个对象作为被观察者Subject,
若干个对象做为观察者Observer,
Subject发生变化时通知Observer你可以看一下java.util.Observable(Subject)和java.util.Observer的源代码ChainOfResponsibility就是责任链模式,
一般接口是
public interface Chain
{
void addChain(Chain nextchain);
void deleteChain(Chain chain);
void handle(.....);
}
可以通过addChain将各个链串连起来,
如果当前链无法handle,则在handle中可以调用nextchain.handle(...)
将处理交给下一个链,这样子持续下去直到有一个链能够处理它,则结束链并返回,
也可以在每个链中处理自己要处理的事情,并交由下一个连处理其它的事情在这个应用中,譬如如果你想写一个日志,
那么你只要在链中串入一个写日志的链,就可以很方便地实现该功能而无
需改变原有的类的结构(当然除了将这些链串接在一起的Client程序)
在改动不大的前提下(以服务器为中心不建立C2C连接)我建议你可以这样试一下.注意:
1.其实服务器针对每个用户是两条线程在运行,一条线程管输入另一条管输出,客户端也是如此;
2.客户端发出的消息中不但需要包括他的内容还需要包括该消息需要发送给何人
3.不要采用查找公用资源(堆栈,Vector等等),而应该采用入栈,弹栈的方式.思路
假设a 用户发向 b用户.服务器段有N多对(输入/输出)线程.当a1(输入线程)从睡眠中醒来(怎么醒来?可以睡一定时间或者干脆睡去靠别人唤醒)侦侧到有消息到来时从Socket中得到输入信息时将其加入堆栈(Vector等)中,需要添加消息发向何处的信息.a1再次进入睡眠状态.b2(向b客户端的输出线程)从睡眠中醒来侦测堆栈中的最后入栈的信息是否为发送给b的,如果不是则继续睡眠,如果是则将该信息发送到b客户端并将该信息弹栈,随后b2进入睡眠状态.
其实关于b2这个地方你可以想想看是否可以使用一个线程来代替所有的发送线程.至少我看过消息中间件有类似的做法.当然这种一直依靠服务器做SWITCH的方式在用户数量众多的情况下效率一定会受到影响.
//接受信息线程
public Receiver extends Thread
{
public Receiver(Socket socket, Observable observable)
{
....
}
public void run()
{
...阻塞等待接受消息,直到接收到消息
//可以这样子,将会阻塞直到接受到信息
//ObjectInputStream ois = new ObjectInputStream(socket.getInputStream);
//接受到消息后observable.notifyObservers(msg)
}
}
//发送消息类
public Sender implements Observer
{
public Sender(Socket socket)
{
....
}
public void update(Observable observable, Object msg)
{
//发送msg
}
}
public Server extends Observable
{
public Server(MainServer ms)
{
...
}
public void server()
{
//阻塞等待连接
//连接之后,创建一个Receiver和一个Sender,调用ms.login(id, sender)
//封装一个XXID登陆信息
//调用notifyObservers(msg)
}
public void notifyObservers(Object o)
{
setChanged();
ms.handleMessage(this, o);
clearChanged();
}
}
public MainServer implements Chain
{
private HashMap senders;//Map.Entry的key为用户登陆ID,value为一个连接用户的socket构造的Sender
public void login(String id, Sender sender)
{
//将登陆信息写入senders
}
public void handleMessage(Observable observable, Object o)
{
//处理该消息(如果是发送给所有,可调用observable.notifyObservers(),否则,可直接从senders中查找到
//该sender,直接调用,并做相应各种处理
}
}
服务器的工组更类似一个接线员,他应该做的是把输入的流接到需要的输出流上。
偶以前做这个东西的时候开发过一个把 InputStream 和 OutputStream 接在一起的类 Pipe,不过性能不佳。
这样,在服务器端保存的东西应该是一张注册表,上面登记了所有已经登陆的 Client 的标识 和其输入流输出流。
每当有新的呼叫的时候,Client 唤醒服务器进行接线,然后服务器去睡觉。
以前我的聊天不能正常进行是我把所有的消息都放到一个消息列表中去,然后由各socket监听线程去找到对应的消息,然后再发送出去,但是socket的消息监听是会堵塞(以前我没有考虑到这一点,我以为socket里面的消息监听过程是一个不停地循环过程)的,这导致后面的消息转发处理过程不能正常进行,现在发现了这一问题,终于把他给解决了。