想要建立多客户端即时通信,必须具有这几个条件(类);
1、客户端;
2、服务器;
3、消息类(数据封包);
4、消息类型。
Demo;
package Task.demo;
import java.io.Serializable;
public class Message implements Serializable {
private String from;//发送者
private String to;//接收者
private int type;//消息类型
private String info;//消息内容
public Message(){
}
public Message(String from, String to, int type, String info) {
this.from = from;
this.to = to;
this.type = type;
this.info = info;
}
public String toString() {
return "Message{" +
"from='" + from + '\'' +
", to='" + to + '\'' +
", type=" + type +
", info='" + info + '\'' +
'}';
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
package Task.demo;
public final class MessageType {
public static final int TYPE_LOGIN=0x1;//登录消息类型
public static final int TYPE_SEND=0x2;//正常聊天的消息类型
}
package Task.demo;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {//服务器
public static void main(String[] args){
//用来保存与客户端通信的用户线程(UserThread)
Vector vector=new Vector<>();
ExecutorService es= Executors.newFixedThreadPool(5);
//TCP协议
try {
ServerSocket server = new ServerSocket(9988);
System.out.println("服务器已启动,正在等待客户端连接");
while (true){
Socket socket = server.accept();//等待客户端连接,此方法会阻塞
UserThread user=new UserThread(socket,vector);
//把runnable接口作为一个任务,传入线程池中,
// 那么线程池会启动一个线程来执行这个任务
es.execute(user);
}
}catch (IOException e){
e .printStackTrace();
}
}
}
//处理客户端消息的线程
class UserThread implements Runnable{
private String name;//代表的是客户端唯一的昵称
private Socket socket;//代表此线程任务服务的客户端socket
private Vector vector;
private ObjectInputStream in;//对象输入流,读取
private ObjectOutputStream out;//对象输出流,写入
private boolean flag=true;//循环的标记
public UserThread(Socket socket, Vector vector) {
this.socket = socket;
this.vector = vector;
this.vector.add(this);
}
public void run(){
//1、谁连接了
System.out.println("客户端"+socket.getInetAddress().getHostAddress()+"已连接");
//2、初始化输入输出流
try {
in = new ObjectInputStream(socket.getInputStream());
out = new ObjectOutputStream(socket.getOutputStream());
//3、循环读取消息
while (flag) {
Message m = (Message) in.readObject();
//4、判断消息的类型
switch (m.getType()) {
case MessageType.TYPE_SEND:
String to = m.getTo();
int size = vector.size();
UserThread ut;
for (int i = 0; i < size; i++) {
ut = vector.get(i);
if (to.equals(ut.name) && ut != this) {
ut.out.writeObject(m);//找到了客户端所对应的中转线程,
// 通过中转线程把消息发送给客户端
break;
}
}
break;
case MessageType.TYPE_LOGIN:
name = m.getFrom();
m.setInfo("欢迎你:");
out.writeObject(m);
break;
}
}
in.close();
out.close();
//5、根据不同的消息类型做相应的处理
}catch (EOFException e){
flag=false;
System.out.println("客户端"+socket.getInetAddress().getHostAddress()+"已断开");//提示
}catch (IOException e){
e.printStackTrace();
}catch (ClassNotFoundException e){
e.printStackTrace();
flag=false;
}
}
}
package Task.demo;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Client {//客户端
public static void main(String[] args){
Scanner input =new Scanner(System.in);
ExecutorService es= Executors.newSingleThreadExecutor();//单线程
try{
Socket socket = new Socket("Localhost",9988);
System.out.println("服务器连接成功");
ObjectOutputStream out =new ObjectOutputStream(socket.getOutputStream());
ObjectInputStream in =new ObjectInputStream(socket.getInputStream());
//====模拟用户登录====
//向服务器发送登录消息
System.out.println("请输入昵称:");
String name=input.nextLine();
//封装数据包
Message m = new Message (name, null , MessageType.TYPE_LOGIN, null);
out.writeObject(m); //向服务器发消息
//从服务器读取消息
m = (Message) in.readObject();
System. out . println(m. getInfo()+m. getFrom());
//=====模拟用户登录结束=====
//启动读取消息的线程
es.execute(new ReadInfoThread(in));
//通过主线程来实现发送消息
boolean flag=true;
while (flag){
m=new Message();
System.out.println("to:");
m.setTo(input.nextLine());
System.out.println("Info:");
m.setInfo(input.nextLine());
m.setFrom(name);
m.setType(MessageType.TYPE_SEND);
out.writeObject(m);
}
}catch (IOException e){
e.printStackTrace();
}catch (ClassNotFoundException e){
e.printStackTrace();
}
}
}
class ReadInfoThread implements Runnable{
private ObjectInputStream in;
private boolean flag=true;
public ReadInfoThread (ObjectInputStream in) {
this.in = in;
}
public void setFlag(boolean flag){
this.flag=flag;
}
public void run() {
while (flag){
try{
Message message=(Message) in.readObject();
System.out.println("["+message.getFrom()+"]对我说:"+message.getInfo());
}catch (IOException e){
e.printStackTrace();
}catch (ClassNotFoundException e){
e.printStackTrace();
}
}
if(in!=null){
try{
in.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
运行结果:
服务器
客户端 1
客户端2