level 10
因帅判自杀
楼主
package day05.chat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 服务端应用程序
* @author Administrator
*
*/
public class Server {
//ServerSocket运行在服务端的Socket
private ServerSocket server;
//保存所有客户端输出流的集合,用于共享以便广播
private List<PrintWriter> allOut;
//线程池
private ExecutorService threadPool;
/**
* 构造方法,用于初始化服务端
*/
public Server(){
try {
server = new ServerSocket(Config.getKeyToInt("server_port"));
allOut = new ArrayList<PrintWriter>();
threadPool = Executors.newFixedThreadPool(40);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 向共享集合中添加一个客户端的输出流
* @param pw
*/
public synchronized void addOut(PrintWriter pw){
allOut.add(pw);
}
/**
* 将给定的客户端的输出流从共享集合中删除
* @param pw
*/
public synchronized void removeOut(PrintWriter pw){
allOut.remove(pw);
}
/**
* 将给定的消息转发给所有的客户端
* @param message
*/
public synchronized void sendMessageToAllClient(String message){
for(PrintWriter pw : allOut){
pw.println(message);
}
}
/**
* 启动服务端的方法
*/
public void start(){
try {
//监听8088端口,等待客户端的连接
/*
* accept方法是一个阻塞方法,直到一个客户端
* 连接,该方法会返回针对该客户端的Socket
* 也就是说,通过这个Socket就可以与连接上
* 的客户端进行交互了
*/
while(true){
System.out.println("等待客户端连接...");
Socket socket = server.accept();
System.out.println("客户端连接了.");
/*
* 当一个客户端连接后,
* 启动一个线程(ClientHandler),将连接的
* 客户端的Socket传入。
*/
ClientHandler handler
= new ClientHandler(socket);
//创建线程,指派任务并启动
// Thread thread = new Thread(handler);
// thread.start();
//将任务交给线程池
threadPool.execute(handler);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
Server server = new Server();
server.start();
}
/**
* Server用于处理不同客户端的多线程任务。
* 该类主要负责与给定的客户端进行交互
* @author Administrator
*
*/
class ClientHandler implements Runnable{
//用于交互的客户端Socket
private Socket socket;
/**
* 构造该线程任务的同时要求指派需要交互的
* 客户端的Socket
* @param socket
*/
public ClientHandler(Socket socket){
this.socket = socket;
}
public void run() {
//定义在try外面,保证finally可以关闭它
PrintWriter pw = null;
try {
/*
* 线程启动后,我们首先获取该客户端的
* 输出流,将其放入共享集合。
*/
OutputStream out
= socket.getOutputStream();
OutputStreamWriter osw
= new OutputStreamWriter(out,"UTF-8");
pw = new PrintWriter(osw,true);
//将该客户端的输出流存入共享集合
addOut(pw);
/*
* 输出当前在线人数:
* 思路:
* 保存所有输出流的集合中有多少元素
* 就说明有多少个用户,所以我们直接
* 输出集合的元素数量即可
*/
System.out.println(
"当前在线人数:"+allOut.size());
//获取远端(客户端)的信息
InetAddress inet
= socket.getInetAddress();
System.out.println(
"客户端端口:"+socket.getPort());
System.out.println(
"客户端完全限定名:"+inet.getCanonicalHostName());
/*
* 服务端这边我们通过该客户端的Socket
* 获取输入流,来读取客户端发送过来的
* 信息
*/
//java.io.InputStream
InputStream in
= socket.getInputStream();
InputStreamReader isr
= new InputStreamReader(in,"UTF-8");
BufferedReader br
= new BufferedReader(isr);
/*
* windows与linux的差异
* 对于客户端主动断开连接后
* windows通过输入流读取数据时会
* 抛出异常。
* br.readLine()//抛出异常
*
* linux则通过输入流读取数据时获取null
* br.readLine()//返回值为null
* 对于缓冲字符输入流的readLine方法
* 若返回值为null,表示任何数据可读了
*/
String line = null;
/*
* 第一次读取到的用户输入的信息是
* 该用户的昵称
*/
String nickName = br.readLine();
while((line = br.readLine()) != null){
// System.out.println(
// "客户端说:"+br.readLine());
/*
* 每当读取到客户端发送过来的消息后
* 就广播给所有客户端
*/
sendMessageToAllClient(nickName+"说:"+line);
}
} catch (Exception e) {
} finally{
/*
* 无论是否正常交互完毕,最终都要与该
* 客户端断开连接
*/
try {
/*
* 首先,当服务端要与客户端断开连接
* 前,先将该客户端的输出流从共享
* 集合中删除,这样,后续的消息就不用0
* 转发给该客户端了。
*/
removeOut(pw);
/*
* 当一个客户端下线后,同样输出
* 当前在线人数
*/
System.out.println(
"当前在线人数:"+allOut.size());
/*
* 关闭Socket那么通过该Socket
* 获取的输入与输出流就全部关闭
* 了
*/
socket.close();
} catch (IOException e) {
}
}
}
}
}
2014年12月03日 00点12分
1
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 服务端应用程序
* @author Administrator
*
*/
public class Server {
//ServerSocket运行在服务端的Socket
private ServerSocket server;
//保存所有客户端输出流的集合,用于共享以便广播
private List<PrintWriter> allOut;
//线程池
private ExecutorService threadPool;
/**
* 构造方法,用于初始化服务端
*/
public Server(){
try {
server = new ServerSocket(Config.getKeyToInt("server_port"));
allOut = new ArrayList<PrintWriter>();
threadPool = Executors.newFixedThreadPool(40);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 向共享集合中添加一个客户端的输出流
* @param pw
*/
public synchronized void addOut(PrintWriter pw){
allOut.add(pw);
}
/**
* 将给定的客户端的输出流从共享集合中删除
* @param pw
*/
public synchronized void removeOut(PrintWriter pw){
allOut.remove(pw);
}
/**
* 将给定的消息转发给所有的客户端
* @param message
*/
public synchronized void sendMessageToAllClient(String message){
for(PrintWriter pw : allOut){
pw.println(message);
}
}
/**
* 启动服务端的方法
*/
public void start(){
try {
//监听8088端口,等待客户端的连接
/*
* accept方法是一个阻塞方法,直到一个客户端
* 连接,该方法会返回针对该客户端的Socket
* 也就是说,通过这个Socket就可以与连接上
* 的客户端进行交互了
*/
while(true){
System.out.println("等待客户端连接...");
Socket socket = server.accept();
System.out.println("客户端连接了.");
/*
* 当一个客户端连接后,
* 启动一个线程(ClientHandler),将连接的
* 客户端的Socket传入。
*/
ClientHandler handler
= new ClientHandler(socket);
//创建线程,指派任务并启动
// Thread thread = new Thread(handler);
// thread.start();
//将任务交给线程池
threadPool.execute(handler);
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
Server server = new Server();
server.start();
}
/**
* Server用于处理不同客户端的多线程任务。
* 该类主要负责与给定的客户端进行交互
* @author Administrator
*
*/
class ClientHandler implements Runnable{
//用于交互的客户端Socket
private Socket socket;
/**
* 构造该线程任务的同时要求指派需要交互的
* 客户端的Socket
* @param socket
*/
public ClientHandler(Socket socket){
this.socket = socket;
}
public void run() {
//定义在try外面,保证finally可以关闭它
PrintWriter pw = null;
try {
/*
* 线程启动后,我们首先获取该客户端的
* 输出流,将其放入共享集合。
*/
OutputStream out
= socket.getOutputStream();
OutputStreamWriter osw
= new OutputStreamWriter(out,"UTF-8");
pw = new PrintWriter(osw,true);
//将该客户端的输出流存入共享集合
addOut(pw);
/*
* 输出当前在线人数:
* 思路:
* 保存所有输出流的集合中有多少元素
* 就说明有多少个用户,所以我们直接
* 输出集合的元素数量即可
*/
System.out.println(
"当前在线人数:"+allOut.size());
//获取远端(客户端)的信息
InetAddress inet
= socket.getInetAddress();
System.out.println(
"客户端端口:"+socket.getPort());
System.out.println(
"客户端完全限定名:"+inet.getCanonicalHostName());
/*
* 服务端这边我们通过该客户端的Socket
* 获取输入流,来读取客户端发送过来的
* 信息
*/
//java.io.InputStream
InputStream in
= socket.getInputStream();
InputStreamReader isr
= new InputStreamReader(in,"UTF-8");
BufferedReader br
= new BufferedReader(isr);
/*
* windows与linux的差异
* 对于客户端主动断开连接后
* windows通过输入流读取数据时会
* 抛出异常。
* br.readLine()//抛出异常
*
* linux则通过输入流读取数据时获取null
* br.readLine()//返回值为null
* 对于缓冲字符输入流的readLine方法
* 若返回值为null,表示任何数据可读了
*/
String line = null;
/*
* 第一次读取到的用户输入的信息是
* 该用户的昵称
*/
String nickName = br.readLine();
while((line = br.readLine()) != null){
// System.out.println(
// "客户端说:"+br.readLine());
/*
* 每当读取到客户端发送过来的消息后
* 就广播给所有客户端
*/
sendMessageToAllClient(nickName+"说:"+line);
}
} catch (Exception e) {
} finally{
/*
* 无论是否正常交互完毕,最终都要与该
* 客户端断开连接
*/
try {
/*
* 首先,当服务端要与客户端断开连接
* 前,先将该客户端的输出流从共享
* 集合中删除,这样,后续的消息就不用0
* 转发给该客户端了。
*/
removeOut(pw);
/*
* 当一个客户端下线后,同样输出
* 当前在线人数
*/
System.out.println(
"当前在线人数:"+allOut.size());
/*
* 关闭Socket那么通过该Socket
* 获取的输入与输出流就全部关闭
* 了
*/
socket.close();
} catch (IOException e) {
}
}
}
}
}