以下代码可以实现服务端发送一条消息,多个客户端可以同时收到这条消息,同时客户端可以单独的和服务端通信
需要注意的是,此时服务端只需要一个发送消息的进程
服务端代码:
/**
* 实现多个客户端对应一个服务端进行通信
*
* @author wangjue
*
*/
public class MyServer {
private ArrayList<Socket> list = new ArrayList<Socket>();
public static void main(String[] args) {
MyServer ms = new MyServer();
ms.initServer(10010);
}
public void initServer(int port) {
try {
ServerSocket server = new ServerSocket(port);
System.out.println("服务端正等待客户端连接...");
/*
* 启动发消息的线程
* 因为是一个服务端对应多个客户端,因此发送消息的线程只需要一个,不需要随着客户端的个数增加而增加
*/
SendThread st = new SendThread(list);
new Thread(st).start();
// 表示可以连接多个客户端
while (true) {
Socket socket = server.accept();
list.add(socket);
System.out.println("已经有一个客户端连接上来了...");
//启动收消息的线程
RecieveThread rt = new RecieveThread(socket);
new Thread(rt).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 接收客户端不断传来消息的线程
*
* @author wangjue
*
*/
public class RecieveThread implements Runnable {
private Socket socket;
private String recieveMsg;
public RecieveThread(Socket socket) {
this.socket = socket;
}
public String getRecieveMsg() {
return recieveMsg;
}
@Override
public void run() {
try {
InputStream ips = socket.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while (true) {
int t = ips.read();
// 收到换行符为止
while (t != '\n') {
bos.write(t);
t = ips.read();
}
byte[] b = bos.toByteArray();
recieveMsg = new String(b);
System.out.println(recieveMsg);
bos.reset();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 发送消息给多个客户端的线程
* @author wangjue
*
*/
public class SendThread implements Runnable {
private ArrayList<Socket> list;
public SendThread(ArrayList<Socket> list) {
this.list = list;
}
@Override
public void run() {
try {
while (true) {
//wait for scanner input,scanner是阻塞性,若没有输出内容,代码会停止不往下执行
Scanner sc = new Scanner(System.in);
String msg = "服务端说:" + sc.nextLine() + "----" + new Date(System.currentTimeMillis()) + "\n";
//通过for循环依次取出所有已经连上的socket对象,将服务端发出的消息写到输入流
for (int i = 0; i < list.size(); i++) {
OutputStream ops = list.get(i).getOutputStream();
ops.write(msg.getBytes());
ops.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
客户端代码
public class MyClient {
public static void main(String[] args) {
MyClient mc = new MyClient();
mc.initClient("127.0.0.1", 10010);
}
public void initClient(String host, int port) {
try {
Socket socket = new Socket(host, port);
talkUI ui = new talkUI();
ui.initUI();
// 启动收消息的线程
RecieveThread rt = new RecieveThread(socket, ui);
new Thread(rt).start();
// 启动发消息的线程
SendThread st = new SendThread(socket, ui);
new Thread(st).start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 接收服务端传来的消息并显示在面板
* @author wangjue
*
*/
public class RecieveThread implements Runnable {
private Socket socket;
private talkUI ui;//传入面板对象,调用getArea1方法获取area1对象
public RecieveThread(Socket socket,talkUI ui) {
this.socket = socket;
this.ui = ui;
}
@Override
public void run() {
try {
InputStream ips = socket.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while (true) {
int t = ips.read();
while (t != '\n') {
bos.write(t);
t = ips.read();
}
byte[] b = bos.toByteArray();
//收到服务端传来的消息
String msg = new String(b);
//将消息显示在消息面板上
ui.getArea1().append(msg+"\n");
//将服务端的消息接收到并显示在面板后,清空输入流,下次收到消息后就不会显示上次已经收到的消息
bos.reset();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 向服务端发送消息
* @author wangjue
*
*/
public class SendThread implements Runnable {
private Socket socket;
private talkUI ui;
public SendThread(Socket socket, talkUI ui) {
this.socket = socket;
this.ui = ui;
}
@Override
public void run() {
try {
ui.ops = socket.getOutputStream();
while (true) {
if(ui.sendMsg2!=null){
byte[] b = ui.sendMsg2.getBytes();
ui.ops.write(b);
ui.ops.flush();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 聊天面板
* @author wangjue
*
*/
public class talkUI implements ActionListener{
private JTextArea area1 = new JTextArea(15,30);
private JTextArea area2 = new JTextArea(10,30);
public OutputStream ops;
//在对话框输入的内容
private String sendMsg;
//传给服务端的内容
public String sendMsg2;
public JTextArea getArea1() {
return area1;
}
public void initUI() {
JFrame jf = new JFrame();
jf.setTitle("私人聊天室");
jf.setSize(400,600);
FlowLayout layout = new FlowLayout();
jf.setLayout(layout);
//显示面板
area1.setEditable(false);
jf.add(area1);
//输入面板
jf.add(area2);
//发送按钮
JButton btn = new JButton("发送");
jf.add(btn);
jf.setDefaultCloseOperation(3);
jf.setVisible(true);
btn.addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
sendMsg = area2.getText();
sendMsg2 = sendMsg+"\n"; //传给服务端的消息要加入换行符,服务端才能知道什么时候结束接收
//输入的内容要显示在面板上
area1.append("自己说:"+sendMsg+"----"+new Date(System.currentTimeMillis())+"\n");
//点击发送后,输入面板要清空
area2.setText("");
//要每点击一次发送就要将内容写入输出流中
try {
ops.write(sendMsg2.getBytes());
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
结果显示