我的程序里面多个客户端在获得服务器更新的在线用户列表时,出现错误。获得列表的思想是:每当一个客户端链接服务器时,客户端会发送自己的登录名给服务器,这时候服务器就同步更新服务器里的在线用户列表(用vector保存),并将更新后的用户列表发送到每个链接服务器的客户端上。 客户端在接受消息的时候,判断接收的是用户列表的时候,便更新客户端本地的在线用户列表(更新后的列表会显示到客户端界面上),但是在显示的时候,只有最近的一个客户端能正常显示在线用户列表,而前面启动的客户端却不能更新在线用户列表。 不知道错误出现在哪儿?我的部分程序如下:服务器端:public final class Server implements Serializable{
private Hashtable<Socket, ObjectOutputStream> clients;
private Object clientsLock;
private static Vector<String> userList;
//.........
//.........
public void startService() {
ServerSocket serverSocket=null;
Socket clientSocket; try {
serverSocket=new ServerSocket(port);
while(true) {
clientSocket=serverSocket.accept();
System.out.println("[" + clientSocket.toString() + "] login...");
new ServerThread(clientSocket).start();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
clientSocket=null;
if(serverSocket!= null) {
serverSocket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}private class ServerThread extends Thread {
private Socket clientSocket; public ServerThread(Socket socket) {
this.clientSocket=socket;
}
public void run() {
ObjectInputStream socketIn=null;
ObjectOutputStream socketOut=null;
String logName=""; try {
socketIn=new ObjectInputStream(this.clientSocket.getInputStream());
socketOut=new ObjectOutputStream(this.clientSocket.getOutputStream());
synchronized(logRegServer.this.clientsLock) {
if(!logRegServer.this.clients.containsKey(clientSocket)) {
logRegServer.this.clients.put(this.clientSocket, socketOut);
}
}
Object readingObject;
/**消息标识*/
String messageType;
/**消息内容*/
String messageInformation;
Enumeration<Socket> allKeys;
Socket otherSocket; /**遍历在线用户时的临时流变量*/
ObjectOutputStream otherSocketOut;
while ((readingObject=socketIn.readObject())!= null) {
if (readingObject instanceof String) {
messageType=(String)readingObject;
if(messageType.equals("NAME")){
//这里用户登录后,会发送用户名给服务器,用于更新列表
logName=(String)socketIn.readObject();
messageInformation="System> "+logName+" has entered.";
/**更新在线用户列表*/
logRegServer.addUserList(logName);
synchronized(logRegServer.this.clientsLock) {
allKeys=logRegServer.this.clients.keys();
while(allKeys.hasMoreElements()) {
otherSocket=allKeys.nextElement();
// if(!otherSocket.equals(this.clientSocket)) {
otherSocketOut=logRegServer.this.clients.get(otherSocket);
/**向各个客户端发送消息标识*/
otherSocketOut.writeObject("LoginExit"); /**向在线的用户发送该用户登录的消息*/
otherSocketOut.writeObject(messageInformation);
/**向在线的用户发送更新的在线用户列表*/
otherSocketOut.writeObject(
logRegServer.getUserList());
otherSocketOut.flush();
// }
Thread.sleep(1);
}
}
}else if(messageType.equals("EXIT")){
messageInformation="System> "+logName+" has lefted.";
System.out.println(this.clientSocket+" has lefted.");
/**更新在线用户列表*/
// synchronized(logRegServer.this.userListLock){
// userList.removeElement(logName);
// }
logRegServer.removeUserList(logName);
synchronized(logRegServer.this.clientsLock) {
allKeys=logRegServer.this.clients.keys();
while(allKeys.hasMoreElements()) {
otherSocket=allKeys.nextElement();
if(!otherSocket.equals(this.clientSocket)) {
otherSocketOut=logRegServer.this.clients.get(otherSocket);
/**发送消息标识*/
otherSocketOut.writeObject("LoginExit");
/**向在线的用户发送用户退出的消息*/
otherSocketOut.writeObject(messageInformation);
/**向在线的用户发送更新的用户列表*/
otherSocketOut.writeObject(
logRegServer.getUserList());
otherSocketOut.flush();
}
Thread.sleep(1);
}
// }
}
logRegServer.this.clients.remove(this.clientSocket);
}
}
Thread.sleep(1);
}
} catch (Exception e) {
try {
synchronized(logRegServer.this.clientsLock) {
this.clientSocket.close();
logRegServer.this.clients.remove(this.clientSocket);
}
} catch (Exception ee) {
ee.printStackTrace();
}
}
}
}
private Hashtable<Socket, ObjectOutputStream> clients;
private Object clientsLock;
private static Vector<String> userList;
//.........
//.........
public void startService() {
ServerSocket serverSocket=null;
Socket clientSocket; try {
serverSocket=new ServerSocket(port);
while(true) {
clientSocket=serverSocket.accept();
System.out.println("[" + clientSocket.toString() + "] login...");
new ServerThread(clientSocket).start();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
clientSocket=null;
if(serverSocket!= null) {
serverSocket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}private class ServerThread extends Thread {
private Socket clientSocket; public ServerThread(Socket socket) {
this.clientSocket=socket;
}
public void run() {
ObjectInputStream socketIn=null;
ObjectOutputStream socketOut=null;
String logName=""; try {
socketIn=new ObjectInputStream(this.clientSocket.getInputStream());
socketOut=new ObjectOutputStream(this.clientSocket.getOutputStream());
synchronized(logRegServer.this.clientsLock) {
if(!logRegServer.this.clients.containsKey(clientSocket)) {
logRegServer.this.clients.put(this.clientSocket, socketOut);
}
}
Object readingObject;
/**消息标识*/
String messageType;
/**消息内容*/
String messageInformation;
Enumeration<Socket> allKeys;
Socket otherSocket; /**遍历在线用户时的临时流变量*/
ObjectOutputStream otherSocketOut;
while ((readingObject=socketIn.readObject())!= null) {
if (readingObject instanceof String) {
messageType=(String)readingObject;
if(messageType.equals("NAME")){
//这里用户登录后,会发送用户名给服务器,用于更新列表
logName=(String)socketIn.readObject();
messageInformation="System> "+logName+" has entered.";
/**更新在线用户列表*/
logRegServer.addUserList(logName);
synchronized(logRegServer.this.clientsLock) {
allKeys=logRegServer.this.clients.keys();
while(allKeys.hasMoreElements()) {
otherSocket=allKeys.nextElement();
// if(!otherSocket.equals(this.clientSocket)) {
otherSocketOut=logRegServer.this.clients.get(otherSocket);
/**向各个客户端发送消息标识*/
otherSocketOut.writeObject("LoginExit"); /**向在线的用户发送该用户登录的消息*/
otherSocketOut.writeObject(messageInformation);
/**向在线的用户发送更新的在线用户列表*/
otherSocketOut.writeObject(
logRegServer.getUserList());
otherSocketOut.flush();
// }
Thread.sleep(1);
}
}
}else if(messageType.equals("EXIT")){
messageInformation="System> "+logName+" has lefted.";
System.out.println(this.clientSocket+" has lefted.");
/**更新在线用户列表*/
// synchronized(logRegServer.this.userListLock){
// userList.removeElement(logName);
// }
logRegServer.removeUserList(logName);
synchronized(logRegServer.this.clientsLock) {
allKeys=logRegServer.this.clients.keys();
while(allKeys.hasMoreElements()) {
otherSocket=allKeys.nextElement();
if(!otherSocket.equals(this.clientSocket)) {
otherSocketOut=logRegServer.this.clients.get(otherSocket);
/**发送消息标识*/
otherSocketOut.writeObject("LoginExit");
/**向在线的用户发送用户退出的消息*/
otherSocketOut.writeObject(messageInformation);
/**向在线的用户发送更新的用户列表*/
otherSocketOut.writeObject(
logRegServer.getUserList());
otherSocketOut.flush();
}
Thread.sleep(1);
}
// }
}
logRegServer.this.clients.remove(this.clientSocket);
}
}
Thread.sleep(1);
}
} catch (Exception e) {
try {
synchronized(logRegServer.this.clientsLock) {
this.clientSocket.close();
logRegServer.this.clients.remove(this.clientSocket);
}
} catch (Exception ee) {
ee.printStackTrace();
}
}
}
}
客户端:程序是不完整的,因为还有其他代码,太多不好发,不好意思import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.Vector;
import javax.swing.*;
import javax.swing.border.TitledBorder;public final class GUI extends JFrame {
private static final long serialVersionUID=2432611980549259658L;
private static final int serverPort=14444;
private static final String serverHost="127.0.0.1";
/**聊天区用户列表*/
private JComboBox userL;
/**在线用户列表*/
private GUI_userList userList;
String name="";
private class ReceiveThread extends Thread {
private Socket socket=null;
private ObjectInputStream socketIn=null;
private ObjectOutputStream socketOut=null;
private boolean isConnected; public ReceiveThread() {
this.isConnected=false;
} public synchronized boolean connectToServer(int port, String host) {
if (!this.isConnected) {
try {
this.socket=new Socket(host, port);
this.socketOut=new ObjectOutputStream(this.socket.getOutputStream());
this.socketIn=
new ObjectInputStream(this.socket.getInputStream());
this.isConnected=true;
//发送消息标识“name”和用户登录名name
this.sendMessage("NAME");
this.sendMessage(name);
} catch (Exception e) {
this.isConnected=false;
e.printStackTrace();
}
}
return this.isConnected;
}
、
public synchronized boolean sendMessage(String message) {
boolean retVal=false; if (this.isConnected) {
try {
this.socketOut.writeObject(message);
this.socketOut.flush();
retVal=true;
} catch (Exception e) {
e.printStackTrace();
}
}
return retVal;
} public void run() {
try {
String messageType;
String messageInformation;
while (!this.socket.isClosed()) {
messageType=(String)this.socketIn.readObject();
if (messageType.equals("LoginExit")){
/**读取登录或退出的标识*/
messageInformation=(String)this.socketIn.readObject(); /**读取更新后的在线用户列表*/
Vector userlist=(Vector)this.socketIn.readObject();
/**显示消息*/
GUI.this.displayMessage(messageInformation);
/**更新用户列表*/
GUI.this.updateUserList(userlist);
}
sleep(1);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**增加在线用户列表显示*/
private JPanel userListPane(){ JPanel p=new JPanel();
p.setBackground(Color.black);
p.setLayout(new BorderLayout());
userL=new JComboBox();
userList=new GUI_userList();
/**添加滚动条*/
JScrollPane pane=new JScrollPane(userList,ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
pane.setBackground(Color.black);
pane.setBorder(BorderFactory.createTitledBorder(null,"Who's online",
TitledBorder.LEFT,TitledBorder.TOP,this.getFont(),Color.green));
p.add(pane,BorderLayout.CENTER);
p.add(userList.getFilterField(),BorderLayout.NORTH);
p.setBorder(BorderFactory.createTitledBorder(null,"",
TitledBorder.LEFT,TitledBorder.TOP,this.getFont(),Color.white));
return p;
} private ReceiveThread receiveThread; protected void displayMessage(String msg) {
this.chatArea.append(msg + '\n');
}
public GUI(String nm) {
this.name=nm;
this.receiveThread=new ReceiveThread();
} protected void updateUserList(Vector UL){
userL.removeAllItems();
userL.insertItemAt("All", 0);
userL.setSelectedIndex(0);
userList.removeAllItem();
for(Object ul: UL){
System.out.println(ul);
/**更新聊天用户列表*/
userL.addItem(ul);
/**更新在线用户显示列表*/
userList.addItem(ul);
}
}
用户shimo登录后显示的列表和聊天区域:列表: chatArea:
shimo System> shimo has entered.
//这里是liguohua登录后,更新的消息,这里消息能正常更新,但是左边的列表却没有更新。
System> liguohua has entered.
用户liguohua登录后显示的列表和聊天区域:列表: chatArea:
shimo System> liguohua has entered.
liguohua
最近的更新事实上也没有更新.只是他本身就在这个Vector 中。
当有一个上线或是下线的时候 你应该把这个新的Vector 发给各个客户端.
1、只能唤醒在一个资源队列中的wait线程
2、一个线程不能访问两个被同步的共享资源~~~~~