我正在用java设计聊天服务器。通信是基于Http而不是基于套接字的。在客户端,我有一个小程序。在服务器端,我有一个servlet。
Applet:我创建一个新线程来监听传入的消息(GET方法)。主线程用于发送消息(POST消息)。
部分代码是:
public void start() {
System.out.println("Creating new thread");
Thread thread = new Thread(this);
thread.start();
}
private String getNewMessage() {
System.out.println("Inside getNewMessage");
String msg = null;
try {
while(msg == null) {
System.out.println("Trying to listen to servlet");
URL servlet = new URL(getCodeBase(), "NewServlet?mode=msg");
URLConnection con = servlet.openConnection();
con.setUseCaches(false);
DataInputStream din = new DataInputStream(new BufferedInputStream(con.getInputStream()));
msg = din.readUTF();
System.out.println("message read :" + msg);
}
} catch (Exception e) {
e.printStackTrace();
}
return msg + "\n";
}
public void run() {
System.out.println("Inside new thread");
while(true) {
System.out.println("inside first while");
String newMsg = getNewMessage();
chatOutput.append(newMsg);
System.out.println("Appended!!");
}
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String message = chatInput.getText();
chatInput.setText("");
chatOutput.append(message + "\n");
try {
System.out.println("Trying to send msg :" + message);
URL url = new URL(getCodeBase(), "NewServlet");
URLConnection servletConnection = url.openConnection();
servletConnection.setDoInput(true);
servletConnection.setDoOutput(true);
servletConnection.setUseCaches(false);
servletConnection.setRequestProperty("Content-Type", "application/octet-stream");
ObjectOutputStream out = new ObjectOutputStream(servletConnection.getOutputStream());
out.writeObject(message);
out.flush();
out.close();
System.out.println("Message sent!");
} catch (Exception e) {
e.printStackTrace();
}
}
下一个代码来自servlet端。它使用Observable接口来识别并向客户发送消息。
public class NewServlet extends HttpServlet {
// getNextMessage() returns the next new message. // It blocks until there is one.
public String getNextMessage() {
// Create a message sink to wait for a new message from the
// message source.
System.out.println("inside getNextMessage");
return new MessageSink().getNextMessage(source);}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("Inside Doget");
response.setContentType("text/plain");
PrintWriter out = response.getWriter();
out.println(getNextMessage());
}
// broadcastMessage() informs all currently listening clients that there
// is a new message. Causes all calls to getNextMessage() to unblock.
public void broadcastMessage(String message) {
// Send the message to all the HTTP-connected clients by giving the
// message to the message source
source.sendMessage(message); }
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("Inside DoPost");
try {
ObjectInputStream din= new ObjectInputStream(request.getInputStream());
String message = (String)din.readObject();
System.out.println("received msg");
if (message != null) broadcastMessage(message);
System.out.println("Called broadcast");
// Set the status code to indicate there will be no response
response.setStatus(response.SC_NO_CONTENT);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Returns a short description of the servlet.
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "Short description";
}
MessageSource source = new MessageSource();}
class MessageSource extends Observable {
public void sendMessage(String message) {
System.out.println("inside sendMsg");
setChanged();
notifyObservers(message);
}
}
class MessageSink implements Observer {
String message = null; // set by update() and read by getNextMessage()
// Called by the message source when it gets a new message
synchronized public void update(Observable o, Object arg) {
// Get the new message
message = (String)arg;
// Wake up our waiting thread
notify();
}
// Gets the next message sent out from the message source
synchronized public String getNextMessage(MessageSource source) {
// Tell source we want to be told about new messages
source.addObserver(this);
System.out.println("AddedObserver");
// Wait until our update() method receives a message
while (message == null) {
try { wait(); } catch (Exception ignored) { }
}
// Tell source to stop telling us about new messages
source.deleteObserver(this);
// Now return the message we received
// But first set the message instance variable to null
// so update() and getNextMessage() can be called again.
String messageCopy = message;
message = null;
System.out.println("Returning msg");
return messageCopy;
}
}
正如您所看到的,我已经包含了System.out.println(“Some message”);在某些地方。这仅用于调试目的。 在Java控制台中,我得到以下输出:
创建新帖子
内部新线程。
在第一时间里面 在getNewMessage里面。
试着听servlet。
在servlet端,我在tomcat日志中获得以下输出:
Inside Doget。
在getNextMessage里面。
AddedObserver。
在applet中输入消息并发送后,我在Java控制台中获得以下输出:
尝试发送消息:你deR ??
消息已发送!
但是在servlet方面,我在日志中没有得到任何东西。
我使用O'Reily Java Servlet Programming作为参考(观察者界面来自那里)。但我没有得到两个客户之间的任何聊天通信。从日志中可以理解,不会调用doPOST
方法。 这是什么原因?
答案 0 :(得分:1)
我通过在applet端发送消息后接收消息(状态消息)来解决问题。在servlet端,在doPost
方法中,我在阅读消息后发送了状态消息("1"
)。
我不知道这究竟是如何解决这个问题的,但我想因为我有setDoInput(true);
,所以它正在等待阅读一些消息。
无论如何,好消息是我至少得到了上述调试过程的预期结果。
此外,有必要在ObjectInputStream
方法中使用DataInputStream
而不是getNewMessage
(因为消息是由ObjectOutputStream发送的)。现在聊天服务器运行顺畅。