返回信息流功能:服务器可以接受多个连接,对于任何客户端所有发送给服务器的数据,将转发给所有客户端(包括发送端)。
package garbagebroadcaster.java;
import java.io.*;
import java.net.*;
import java.util.*;
public class Server extends Thread {
private ServerSocket serverSocket;
private Set<ClientHandler> clientHandlers = new HashSet<ClientHandler>();
@Override
public void run() {
try {
serverSocket = new ServerSocket(9966);
while (true) {
Socket clientSocket = serverSocket.accept();
new ClientHandler(clientSocket).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
serverSocket.close();
} catch (IOException e) {
// We have to give up.... :(
e.printStackTrace();
}
}
}
private class ClientHandler extends Thread {
private Socket clientSocket;
private PrintWriter writer;
public ClientHandler(Socket clientSocket) throws IOException {
this.setDaemon(true);
this.clientSocket = clientSocket;
this.writer = new PrintWriter(clientSocket.getOutputStream());
synchronized (clientHandlers) {
clientHandlers.add(this);
}
}
public void send(String message) {
synchronized (writer) {
writer.println(message);
writer.flush();
}
}
@Override
public void run() {
try {
Scanner scanner = new Scanner(clientSocket.getInputStream());
while (true) {
String line = scanner.nextLine();
synchronized (clientHandlers) {
for (ClientHandler ch : clientHandlers) {
ch.send(line);
}
}
}
} catch (IOException e) {
// Have to give up.
e.printStackTrace();
} catch (NoSuchElementException e) {
// Socket closed.
// Do nothing.
} finally {
try {
clientSocket.close();
} catch (IOException e) {
// ... because this is fatal...
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
new Server().start();
}
}
这是一条镜像帖。来源:北邮人论坛 / java / #14005同步于 2010/4/15
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖
这个程序有什么隐患吗
wks
2010/4/15镜像同步8 回复
订阅后,新回复会通过你的通知中心匿名送达。
8 条回复
错误不少。
1, public void send(String message) {
synchronized (writer) {
writer.println(message);
writer.flush();
}
}
writer是线程专有的,还同步个什么劲。
2, while (true) {
String line = scanner.nextLine();
synchronized (clientHandlers) {
for (ClientHandler ch : clientHandlers) {
ch.send(line);
}
}
}
scanner是服务端的输入流,在等客户端的数据,但这段代码在客户端,每个客户端是单线程,所以不可能有机会发给服务器数据。死锁形成了。
3,这个程序我还没运行。但看这种设计就是很垃圾的。
运行了,根本就是一团糟,不知lz想干啥。。
建议lz从基础学起。
先把多线程搞清楚,掌握同步机制,然后再看socket。
另外既然是初学者就不要把多个类写在一起,一步一个脚印去学。。
accept那阻塞了,不过要是用timer让client那个晚点运行不知会怎样。。。
【 在 wks (cloverprince) 的大作中提到: 】
: 功能:服务器可以接受多个连接,对于任何客户端所有发送给服务器的数据,将转发给所有客户端(包括发送端)。
: package garbagebroadcaster.java;
: import java.io.*;
: ...................
【 在 greedisgood 的大作中提到: 】
: 错误不少。
: 1, public void send(String message) {
: synchronized (writer) {
: ...................
解释一下
1. send方法会被别的线程调用。(但是,凡是调用send的线程,都会锁住clientHandlers,所以writer似乎也不用锁)
2. 这里全部都是服务器端代码(所以叫ClientHandler而不是Client)。客户端是telnet.exe或者nc
【 在 wks 的大作中提到: 】
: 解释一下
: 1. send方法会被别的线程调用。(但是,凡是调用send的线程,都会锁住clientHandlers,所以writer似乎也不用锁)
: 2. 这里全部都是服务器端代码(所以叫ClientHandler而不是Client)。客户端是telnet.exe或者nc
所以writer不用锁。
如果用telent,那就没死锁了。
【 在 greedisgood 的大作中提到: 】
: 运行了,根本就是一团糟,不知lz想干啥。。
: 建议lz从基础学起。
: 先把多线程搞清楚,掌握同步机制,然后再看socket。
: ...................
哈哈 这回复有意思。。。
目前已经发现的问题:
1. 客户断开时没有更新clientHandlers集合。
2. send可能阻塞(OutputStream.write阻塞)。如果有一个send被阻塞,那么这个线程在阻塞解除前,就不能从它对应的客户读取数据了。但不会死锁。