package com.company.Server.model;
/**
* @Title:
* @Package
* @Description: 服务器和客户端通信线程
* @author: Yeeasy
**/
import com.company.Client.tools.TalkingViewManage;
import com.company.Client.tools.UserThreads;
import com.company.Client.tools.UserThreadsManage;
import com.company.Client.view.TalkingView;
import com.company.Shared.Message;
import java.net.*;
import java.io.*;
public class ConnectThread extends Thread {
Socket socket;
public ConnectThread(Socket socket) {
this.socket = socket;
}
public void run() {
while (true) {
try {
//接受信息
ObjectInputStream in;
ObjectOutputStream out;
in = new ObjectInputStream(socket.getInputStream());
Message msg = (Message) in.readObject();
//从usersThread中获取friend线程,转发信息
UserThreads userThread= UserThreadsManage.getUserThreads(msg.getUser());
out = new ObjectOutputStream(userThread.getSocket().getOutputStream());
out.writeObject(msg);
TalkingView talkingView= TalkingViewManage.getTalkingView(msg.getUser());
talkingView.showMessage(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
你这里有三个问题:
UserThreadsManage.addUserThreads(u.getUserID(), new UserThreads(socket));
TalkingView talkingView= TalkingViewManage.getTalkingView(msg.getUser());
而且正常服务端也应该是通过socket 转发消息给客户端,而不是直接操作客户端的界面显示
不知道你这个问题是否已经解决, 如果还没有解决的话:问题:
在一个用户给另一个仍未上线的用户(即离线用户)发送消息时,由于对方用户离线,服务端会将message先存储起来,等待该用户上线再转发message给他。但是当我这样处理的时候,出现了如下错误。
java.io.StreamCorruptedException: invalid stream header: 7371007E
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:936)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:394)
at com.hspedu.qqclient.service.ClientConnectServerThread.run(ClientConnectServerThread.java:23)
而且,我发现,该离线用户一旦上线,服务端是会正常发送他离线期间收到的信息给他的,关键是接收出了问题。
服务端没有报错:
客户端报错,但是它是在收到一条正确的离线留言之后才产生错误的:
给出关键源代码如下:
服务端
// 将离线消息都发过去
oos=new ObjectOutputStream(ManageClientThreads.getClientThread(user.getUserId()).getSocket().getOutputStream());
if(offlineDb.containsKey(user.getUserId())){
ArrayList<Message> messages = offlineDb.get(user.getUserId());
for (Message offlinems:messages
) {
System.out.println(offlinems.getContent());
oos.writeObject(offlinems);
}
offlineDb.remove(user.getUserId());
System.out.println(user.getUserId()+"上线了,服务端已经转发完成所有离线消息");
}
客户端
package com.hspedu.qqclient.service;
import com.hspedu.qqcommon.Message;
import com.hspedu.qqcommon.MessageType;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
public class ClientConnectServerThread extends Thread{
// 该线程需要持有socket对象
private Socket socket;
//构造器接收socket
public ClientConnectServerThread(Socket socket) {
this.socket = socket;
}
private ObjectInputStream ois;
@Override
public void run() {
// 因为Thread需要后台和服务器通信,所以我们一直循环
while(true){
System.out.println("客户端线程,等待读取从服务器端发送过来的消息");
try {
ois= new ObjectInputStream(socket.getInputStream());
// 如果服务器没有发送Message对象,线程就会阻塞在这里
Message message=(Message)(ois.readObject());
//如果读取到的是服务端返回的在线用户列表
if(message.getMesType().equals(MessageType.MESSAGE_RET_ONLINE_FRIEND)){
//取出在线列表信息并显示
String[] onlineUsers=message.getContent().split(" ");
System.out.println("============当前在线用户列表=============");
for (int i = 0; i < onlineUsers.length; i++) {
System.out.println(onlineUsers[i]);
}
}else if(message.getMesType().equals(MessageType.MESSAGE_COMM_MES)){
//收到私聊信息
System.out.println("我"+message.getGetter()+"收到了来自"+message.getSender()+"的私聊信息:"+message.getContent());
}else if(message.getMesType().equals(MessageType.MESSAGE_TO_ALL_MES)){
//收到群发信息
System.out.println("我收到了来自"+message.getSender()+"的群发信息:"+message.getContent());
}else if(message.getMesType().equals(MessageType.MESSAGE_NEWS)){
System.out.println("我收到了来自服务端推送的新闻:"+message.getContent());
}
else{
System.out.println("是其他类型的message,暂时不处理");
}
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
}
该文件全部源代码:
服务端
package com.hspedu.qqserver.service;
import com.hspedu.qqcommon.Message;
import com.hspedu.qqcommon.MessageType;
import com.hspedu.qqcommon.User;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
public class QQServer {
private ServerSocket ss = null;
// 创建一个集合,存放多个用户,如果是这些用户登录,就认为合法
private static HashMap<String, User> validUsers = new HashMap<>();
private static HashMap<String, ArrayList<Message>> offlineDb =new HashMap<>();
static {//在静态代码块内初始化validUsers
validUsers.put("100", new User("100", "123456"));
validUsers.put("200", new User("200", "123456"));
validUsers.put("300", new User("300", "123456"));
validUsers.put("李东海", new User("李东海", "李赫宰"));
validUsers.put("李赫宰", new User("李赫宰", "李东海"));
}
public static HashMap<String, ArrayList<Message>> getOfflineDb() {
return offlineDb;
}
// 验证用户是否有效的方法
private boolean checkUser(String userId, String password) {
User user = validUsers.get(userId);
if (user != null && user.getPassword().equals(password)) {
return true;
}
return false;
}
public QQServer() {
System.out.println("服务端在9999端口监听...");
try {
ss = new ServerSocket(9999);
SendNewsToAllService sendNewsToAllService = new SendNewsToAllService();
sendNewsToAllService.start();
//当和某个客户端建立连接之后,会继续监听,因为应该用while循环
while (true) {
Socket socket = ss.accept();
//得到socket关联的对象输入流
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
//得到socket关联的对象输出流
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
User user = (User) (ois.readObject());
// 验证
Message message = new Message();
if (checkUser(user.getUserId(), user.getPassword())) {
message.setMesType(MessageType.MESSAGE_LOGIN_SUCCEED);
// 回复客户端一个Message对象
oos.writeObject(message);
//创建一个线程,和客户端保持通信,该线程需要持有socket对象
ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(socket, user.getUserId());
// 启动线程
serverConnectClientThread.start();
// 把该线程对象放到集合中管理
ManageClientThreads.addClientThread(user.getUserId(), serverConnectClientThread);
// 将离线消息都发过去
oos=new ObjectOutputStream(ManageClientThreads.getClientThread(user.getUserId()).getSocket().getOutputStream());
if(offlineDb.containsKey(user.getUserId())){
ArrayList<Message> messages = offlineDb.get(user.getUserId());
for (Message offlinems:messages
) {
System.out.println(offlinems.getContent());
oos.writeObject(offlinems);
}
offlineDb.remove(user.getUserId());
System.out.println(user.getUserId()+"上线了,服务端已经转发完成所有离线消息");
}
} else {
System.out.println("登录失败");
message.setMesType(MessageType.MESSAGE_LOGIN_FAIL);
oos.writeObject(message);
socket.close();
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
客户端
// 客户端全部代码都在上面放了