我正在写一个类似QQ通信系统的程序,但是遇到这样一个问题:
qq中不能同时登陆一个账号,如果这个账号被1端登陆上,但2端也想登陆上,这时候1端被强制退出,于是2端成功登陆上,就避免了两个账号同时登陆的问题
但是我在写程序的时候,发现2端在登陆后,1端确实被强制退出了,2端和服务端抛出了异常:SokectException :Connect Reset
我不清楚这是为什么,代码里 if (newUser != null)代码块是我主题
以下是我的代码
public QQServer() throws IOException {
try {
while (true) {
//得到一个客户端输入的Socket
Socket socket = sockets.accept();
//得到一个对象流
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
User user = (User) objectInputStream.readObject();
//这里是注册操作
//检查是否是要操作注册的用户:看看这个用户的id是否为空,如果为0,则是
if (user.getId() == 0) {
//得到对应的Socket
System.out.println("用户请求注册账户");
RegisterAccount(user, socket);
continue;
}
//下面是登陆操作
//验证账号密码
int id = user.getId();
String password = user.getPassword();
Message message = new Message();
//连接数据库,得到一个User类对象
User newUser = CheckLogin(id, password);
message.setUser(newUser);
//如果这个对象存在
if (newUser != null) {
//下面是验证这个用户是否在线,如果在线,那么在线的那一端就被强制下线,这一点就是新登录的线程
if(CheckOnline(user)!=null){
QQClientConnectServerThread qqClientConnectServerThread = ManageConnectThread.getHashMapSocket(user.getId());
Message message1 = new Message();
message1.setMessageType(MessageType.MESSAGE_EXIT);
//得到一直在登录的Socket
Socket socket1 = qqClientConnectServerThread.getSocket();
//从hashmap中删除这个线程
ManageConnectThread.RemoveHashMapSocket(user.getId());
//发送
new ObjectOutputStream(socket1.getOutputStream()).writeObject(message1);
//关闭这个Socket
//socket1.close();
}
//新的一端成功登陆上
message.setMessageType(MessageType.MESSAGE_LOGIN_SUCCESS);
//创建一个线程类
QQClientConnectServerThread qqClientConnectServerThread = new QQClientConnectServerThread(id, socket);
//将该线程放到hashmap
ManageConnectThread.addHashMapSocket(id, qqClientConnectServerThread);
//将该登陆的账号和姓名插入到OnlineUser里面去
String sql = "insert into onlineUser values(?,?)";
userDao.QueryDML(sql, newUser.getId(), newUser.getName());
//启动该线程
new Thread(qqClientConnectServerThread).start();
//新建一个对象输出流,将message发送过去
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(message);
System.out.println(user.getId() + "已登录系统");
} else {
message.setMessageType(MessageType.MESSAGE_LOGIN_FAIL);
//新建一个对象输出流,将message发送过去
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
objectOutputStream.writeObject(message);
socket.close();
}
}
} catch (IOException | SQLException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
sockets.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
应该是你 socket close 错了,把后来登录的那个给关了。
不知道你这个问题是否已经解决, 如果还没有解决的话:由于没有给出具体的代码,我无法直接分析问题的具体原因和解决方案。但是,根据问题描述和参考资料,我可以提供一些可能的解决方案供你参考:
异常处理: 确保你的代码中针对网络连接异常进行了适当的处理。在Java网络编程中,可以使用try-catch块来捕获和处理异常。你可以捕获SocketException,然后根据具体的异常信息进行处理。例如,当捕获到Connect Reset异常时,可以简单地忽略该异常并继续运行程序。
连接管理: 确保你在程序中正确管理和关闭网络连接。当用户登录成功后,可以为每个用户创建一个独立的Socket连接,并保存在一个连接池中。当发生账号强制退出的情况时,可以通过关闭对应的连接来实现。同时,确保在连接池中及时删除已关闭的连接,以防止后续操作出现异常。
用户登录控制: 在程序中包含一个用户登录管理的模块,用于控制同一账号的多次登录。当一个用户尝试登录时,你可以在登录过程中检查当前账号是否已经被其他用户登录,并根据需要采取相应的措施。例如,当检测到同一账号已经被其他用户登录时,可以发送一个强制退出的消息给之前登录的用户,并关闭对应的连接。
多线程处理: 确保你的程序能够支持并发登录和连接操作。在Java中,可以使用多线程来实现这一点。当一个用户尝试登录时,可以将该操作放到一个独立的线程中进行处理,以便同时处理其他用户的登录请求。同时,对于用户的连接操作,也可以为每个连接创建一个独立的线程来处理,以防止线程阻塞导致登录操作无法进行。
这些只是一些可能的解决方案,具体的实现方式需要根据你的代码和业务逻辑来决定。如果你能提供更多的代码和相关信息,我可以给出更具体的建议。