dos版本的聊天室
目的:实现客户端对客户端的通信
思路:客户端发送信息到服务器(保存客户1的内容),之后判断链接来的客户端是不是某个地址,然后,写出去客户端2。
前提,能实现多用户的连接(Thread)
一、首先创建一个消息类,该类只有两个属性:
- 一是接收消息的客户端的编号
- 二是消息内容
实现代码如下:
package com.xiaogao;
import java.io.Serializable;
/*
* 消息类,该类只有两个属性:
* 一个是接收消息的客户端的编号,一个是消息内容
*/
public class Message implements Serializable{
//客户端编号
int id;
//消息内容
String msg;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
二、然后创建一个服务器,转发客户端信息
package com.xiaogao;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
/*
* 服务器,该类创建了serverSocket对象,绑定本地的8989端口,
* 声明静态变量sessionMap来保存所有已连接的客户端,并给每个客户端分配一个编号
*/
public class SocketNotifyServer {
//socket服务器
ServerSocket serverSocket=null;
//用来存放已连接的客户端的socket信息
static Map<Integer,Socket> sessionMap=new HashMap<Integer,Socket>();
public void socket(){
try {
//创建serverSocket,绑定端口8989
serverSocket =new ServerSocket(8989);
System.out.println("服务器开启!!!");
//客户端编号
int i=1;
//实现多个客户端的连接
while(true){
Socket socket=serverSocket.accept();
System.out.println("客户端:"+i+"连接成功~~~");
if(socket!=null){
//将socket放入map,key为客户端编号
sessionMap.put(i, socket);
//开启线程处理本次对话
Thread thread=new Thread(new NotifyHandler(socket,sessionMap));
thread.setDaemon(true);
thread.start();//启动并运行线程
i++;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException{
new SocketNotifyServer().socket();
}
}
三、接着创建一个消息处理类
利用构造方法,得到消息发送方以及所有的已连接客户端
package com.xiaogao;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Map;
/*
* 消息处理类,重写构造方法,
* 得到消息发送方以及所有的已连接客户端
*/
public class NotifyHandler extends Thread{
Socket socket=null;
InputStream in=null;
Map<Integer,Socket> sessionMap=null;
public NotifyHandler(Socket socket,Map<Integer,Socket> sessionMap){
this.socket=socket;
this.sessionMap=sessionMap;
}
public void run(){
try {
in = socket.getInputStream();
ObjectInputStream ois = new ObjectInputStream(in);
// 实现一次连接多次通话
while (true) {
try {
Message msg = (Message) ois.readObject();
System.out.println("消息接受对象:客户端" + msg.getId() + ",\t消息内容:" + msg.getMsg());
// 发送数据
try {
Socket targetSocket = sessionMap.get(msg.getId());
OutputStream out = targetSocket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(msg);
System.out.println("服务端已转发");
} catch (IOException e) {
e.printStackTrace();
}
if (socket.isClosed()) {
break;
}
} catch (IOException e) {
e.printStackTrace();
try {
socket.close();
break;
} catch (IOException e1) {
e1.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
四、最后是创建客户端
package com.xiaogao;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
/*
* 客户端
*/
public class MsgSocketClient {
Socket socket=null;
InputStreamReader input=null;
InputStream in=null;
OutputStream out=null;
public void socketStart(){
try {
socket=new Socket("127.0.0.1",8989);
System.out.println("客户端1启动————");
//接受返回的数据
new Thread(){
public void run(){
try {
while(true){
in=socket.getInputStream();
ObjectInputStream ois=new ObjectInputStream(in);
Message msg=(Message)ois.readObject();
System.out.println("返回数据:"+msg.getMsg());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
out=socket.getOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(out);
while(true){
input=new InputStreamReader(System.in);//阻塞着等待输入
String msg=new BufferedReader(input).readLine();
Message message=new Message();
message.setId(2);
message.setMsg(msg);
oos.writeObject(message);
System.out.println("已发送");
}
} catch (Exception e) {
e.printStackTrace();
}finally{
//关闭流和连接
try {
in.close();
out.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new MsgSocketClient().socketStart();
}
}
/*
* 当(客户端1)启动的时候id属性的值为2,当(客户端2)启动时,id属性为1。
* 此处把消息接收代码放在前面,是因为while (true){input = new InputStreamReader(System.in);
* 这里在阻塞着等待输入,如果接收消息的代码放在这段代码下方,会导致在没有发过消息的时候,
* 接收消息的线程不会启动,收不到别的客户端发来的消息
*/
此聊天室,可以一方多次发送,解决了一来一回造成的堵塞问题。