简单聊天室 java_JAVA简单聊天室(服务端+客户端)

packagecom;importjava.io.BufferedReader;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.io.OutputStream;importjava.io.OutputStreamWriter;importjava.io.PrintWriter;importjava.net.InetAddress;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;

@SuppressWarnings("unused")public classServer {private ExecutorService threadPool; //线程池,用来管理与客户端交互的线程(重用线程)

private List allOut; //定义一个集合List,存放所有客户端输出流的共享集合

/** java.net.ServerSocket运行在服务端的Socket。主要工作是申请服务端的端口,

* 并且监听该端口, 等待客户端的连接。一旦一个客户端与服务端建立连接,

* ServerSocket会返回与该客户端沟通的Socket。*/

privateServerSocket server;public Server() //服务端构造方法,用来初始化服务端的相关属性

{try{//初始化

server = new ServerSocket(8088);

allOut= new ArrayList();

threadPool= Executors.newFixedThreadPool(50);

}catch(Exception e) {

e.printStackTrace();

}

}private synchronized void addOut(PrintWriter out) //向共享集合中添加给定的输出流

{

allOut.add(out);

}private synchronized void removeOut(PrintWriter out) //删除输出流

{

allOut.remove(out);

}private synchronized void sendMessageToAllClient(String message) //给所有的客户端发送消息

{for(PrintWriter out : allOut)

{

out.println(message);//把要发送的消息发送给这个客户端

}

}//服务端开始工作的方法

public voidstart() {try{//ServerSocket的accept方法:该方法用来监听服务端打开的8088端口//,等待客户端的连接//一旦一个客户端连接了就会返回与该客户端进行通信的Socket。

while(true)

{

System.out.println("等待客户端连接……");

Socket socket=server.accept();//accept是一个阻塞方法,直到一个客户端连接,否则会一直卡在这里

System.out.println("一个客户端连接了!");//启动一个线程,来完成与刚刚连接的客户端的交互工作

ClientHandler handler = newClientHandler(socket);//Thread t = new Thread(handler);//t.start();

threadPool.execute(handler); //把上面单独新建的一个线程,改成可以管理多个线程的线程池来使用

}

}catch(Exception e) {

e.printStackTrace();

}

}public static voidmain(String[] args) {

Server server= newServer();

server.start();

}//定义一个内部类,新建runnable新的线程

class ClientHandler implementsRunnable

{//当前线程用来交互的客户端的Socket

private Socket socket; //创建线程任务的同时指定要交互的客户端的Socket

private String host; //该客户端地址

publicClientHandler(Socket socket)

{//通过Socket我们是可以得知远端计算机的信息

InetAddress address= socket.getInetAddress(); //IP

host =address.getHostAddress();int port = socket.getPort();//端口

System.out.println(host+ "上线");this.socket =socket;

}public voidrun()

{

PrintWriter pw= null;try{

OutputStream out= socket.getOutputStream();//通过socket获取输出流,来将消息发送回给客户端。

OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");

pw= new PrintWriter(osw, true);//(将该输出流存入共享集合中,以便可以广播消息)

addOut(pw); //在内部类用外部类的方法//通过Socket获取输入流,用方法:getInputStream()//InputStream getInputStream(),该方法用来获取一个输入流,//可以读取来自远端计算机发送过来的数据。

InputStream in=socket.getInputStream();

InputStreamReader isr= new InputStreamReader(in,"UTF-8");

BufferedReader br= newBufferedReader(isr);//转换为缓冲字符输入流的目的在于,可以以“行”为单位,读取字符串

String message= null;//由于br.readLine()方法在操作系统的不同,导致客户端和幅度按断开连接后,这个方法的效果是不同的。//linux:当linux的客户端与服务端断开连接后,br.readLine()方法会返回null//windows:当windows的客户端与服务端断开连接后,br.readLine()方法会抛出异常

while((message = br.readLine()) != null) //读取客户端发送过来的一行字符串

{//System.out.println(host + "说:" + message);//pw.println(host + "说:" + message);//将该客户端发送过来的消息,转发给所有客户端,达到广播的目的。

sendMessageToAllClient(host+"说"+message);

}

}catch(Exception e) {

e.printStackTrace();

}finally{//无论是linux的客户端还是windows的客户端,当与我们断开连接后,都应当将Socket关闭,来释放资源

System.out.println(host + "下线了!");//(将该客户端的输出流从共享集合中删除)

removeOut(pw);try{

socket.close();

}catch(Exception e) {

e.printStackTrace();

}

}

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值