Socket(二)基于InputStream和OutputStream实现多人聊天功能
来源:互联网 发布:淘宝助理导出订单 编辑:程序博客网 时间:2024/06/10 21:32
使用Socket进行简单的聊天功能
//在初步了解了Socket的基础知识,了解了Socket的传输之后,简单写一个手机用Socket进行聊天功能的Demo //1.先写一个server和client进行交互的例子 public class Server { public static void main(String[] args) throws IOException { ServerSocket server = new ServerSocket(9999); //设置超时时间,过了时间会自动关闭 server.setSoTimeout(60000*10); Socket client = server.accept(); while(true){ //输入流 DataInputStream dis = new DataInputStream(client.getInputStream()); String a = dis.readUTF(); //输出流 DataOutputStream dos = new DataOutputStream(client.getOutputStream()); dos.writeUTF("服务器--》:"+a); dos.flush(); } } } public class Client { public static void main(String[] args) throws IOException { Socket client = new Socket("localhost", 9999); //从键盘写入 BufferedReader b = new BufferedReader(new InputStreamReader(System.in)); DataOutputStream dos = new DataOutputStream(client.getOutputStream()); DataInputStream dis = new DataInputStream(client.getInputStream()); while(true){ String re = b.readLine(); //输出流 dos.writeUTF(re); dos.flush(); //输入流 String a = dis.readUTF(); System.out.println(a); } } }
server端使用死循环使客户端可以一直访问。
先运行server再运行client,在控制台输入:
得到这样表示已经成功进行了,server和client的通信。(使用流的方式)
为了是程序更加适用,改进client端进行代码分离和多线程使用:
public class Client { public static void main(String[] args) throws IOException { Socket client = new Socket("localhost", 9999); //启动发送线程 new Thread(new Send(client)).start(); //启动接收线程 new Thread(new Receive(client)).start(); } }
提出client的发送和接收方法成单独的目的是让输入和输出流相互独立
使用BufferReader用来进行从键盘的写入(注:BufferReader的readLine()方法是阻塞的,进行到readLine()方法会阻塞,直到接收到键盘输入的数据才会继续运行):
发送类:
/* 注(Client的Send类思路介绍): 新建一个发送的线程。 把Client类中的BufferReader和DataOutputStream提出到send类中 在无惨构造进行BufferReader的初始化 使用有参构造调用BufferReader并初始化DataOutputStream 在线程的run方法里面进行判断,构造输出流是否成功,是成功进行发送操作(提出来的send()) 发送操作(send())分两步: 1.从键盘接收数据(getMesforConsole()方法) 2.发送数据 */ public class Send implements Runnable{ //键盘写入流 private BufferedReader buff; //管道输出流 private DataOutputStream dos; //控制线程的标识 private boolean isRunning = true; //构造器里初始化 public Send() { buff = new BufferedReader(new InputStreamReader(System.in)); } //把管道传进来 public Send(Socket client){ this(); try { dos = new DataOutputStream(client.getOutputStream()); } catch (IOException e) { // e.printStackTrace(); isRunning = false; CloseUtil.closeAll(dos,buff); } } //从控制台接收数据 public String getMesforConsole(){ try { return buff.readLine(); } catch (IOException e) { // e.printStackTrace(); } return ""; } //发送信息 public void send(){ String console = getMesforConsole(); try { if(null != console && console != ""){ dos.writeUTF(console); dos.flush(); } } catch (IOException e) { // e.printStackTrace(); isRunning = false; CloseUtil.closeAll(dos,buff); } } @Override public void run() { while(isRunning){ send(); } }
接收类:
/* 注(Client的Send类思路介绍): 构建接受类run()里面调用接收方法,输出接收到的数据 */ public class Receive implements Runnable{ private DataInputStream dis; private boolean isRunning = true; public Receive() { } public Receive(Socket client){ this(); try { dis = new DataInputStream(client.getInputStream()); } catch (IOException e) { // e.printStackTrace(); isRunning = false; CloseUtil.closeAll(dis); } } /** * 接收数据 * @return */ public String receive(){ String receive = ""; try { receive = dis.readUTF(); } catch (IOException e) { // e.printStackTrace(); isRunning = false; CloseUtil.closeAll(dis); } return receive; } @Override public void run() { while(isRunning){ System.out.println(receive()); } } }
关闭流的工具类CloseUtil:
/** * 关闭所有流,工具类,可关闭多个(传进来多个以“,”分割) * @author Administrator * */ public class CloseUtil { public static void closeAll(Closeable... io){ for(Closeable temp:io){ try { if(null != temp){ temp.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
这个时候只能单个client进行访问,改进server端(支持多客户端访问):
/* 注(Server思路介绍): 构建private List<MyChannel> list = new ArrayList<MyChannel>(); 进行存储所有的管道,也就是客户端的连接每个连接可以称为一个管道 使用list统一管理容器 提出send和reciive方法还有发送给他人的sendOthers(发送给所有人) */ public class Server { private List<MyChannel> list = new ArrayList<MyChannel>(); public static void main(String[] args) throws IOException { //设置超时时间,过了时间会自动关闭 // server.setSoTimeout(60000*10); new Server().start(); } public void start() throws IOException{ ServerSocket server = new ServerSocket(9999); ExecutorService pool = Executors.newFixedThreadPool(2); while(true){ //每隔进来会开启一个线程 Socket client = server.accept(); MyChannel myChannel = new MyChannel(client); //将进来的管道都加进去.加入到容器统一管理 list.add(myChannel);//统一管理 // new Thread(myChannel).start();//一条道路 pool.execute(myChannel); } } //写到内部类里面,便于访问私有信息 private class MyChannel implements Runnable{ private DataInputStream dis; private DataOutputStream dos; private boolean isRunning = true; private String name; //在有参构造初始化 public MyChannel(final Socket client){ try { dis = new DataInputStream(client.getInputStream()); dos = new DataOutputStream(client.getOutputStream()); this.name = dis.readUTF(); send("欢迎进入聊天室"); sendOthers(name+" 加入了聊天室",true); } catch (IOException e) { // e.printStackTrace(); isRunning = false; CloseUtil.closeAll(dis,dos); } } /** * 接收方法 */ public String receive(){ String msg = ""; try { msg = dis.readUTF(); } catch (IOException e) { // e.printStackTrace(); isRunning = false; CloseUtil.closeAll(dis); list.remove(this); } return msg; } /** * 发送给自己方法 */ public void send(String msg){ if(null == msg || msg.equals("")){ return; } try { dos.writeUTF(msg); dos.flush(); } catch (IOException e) { // e.printStackTrace(); isRunning = false; CloseUtil.closeAll(dos); list.remove(this); // sendOthers(name+" 离开了聊天室"); } } /** * 发送给别人的 * @param msg */ public void sendOthers(String msg,boolean sys){//true表示系统发的,false表示给别人发的 if(msg.startsWith("@") && msg.indexOf(":") > -1){ String name = msg.substring(1, msg.indexOf(":")); String context = msg.substring(msg.indexOf(":") + 1); for(MyChannel other:list){ if(other.name.equals(name)){ other.send(this.name+"私聊你说:"+context); } } }else{ for(MyChannel other:list){ if(other == this){ continue; } if(sys){//系统提示信息 other.send("系统信息 "+msg); }else{ other.send(this.name+"对所有人说:"+msg); } } } } @Override public void run() { while(isRunning){ // send(receive());//只发自己 //发送给别人 sendOthers(receive(),false); } } } }
Tip:在实现上述功能的基础上可以进行功能增加,添加客户端用户姓名,和改进让用户进行私聊。
阅读全文
0 0
- Socket(二)基于InputStream和OutputStream实现多人聊天功能
- 基于Socket.IO实现Android聊天功能
- (二)Android socket+多线程 实现聊天功能
- 使用InputStream和OutputStream实现文件复制
- InputStream 和OutputStream
- InputStream 和OutputStream
- InputStream 和OutputStream
- InputStream 和OutputStream
- InputStream 和OutputStream
- inputStream 和outputStream
- InputStream 和OutputStream
- InputStream 和OutputStream
- InputStream 和OutputStream
- InputStream和OutputStream
- InputStream和OutputStream
- InputStream 和OutputStream
- InputStream 和OutputStream介绍
- InputStream 和 OutputStream
- ios实现UITableView 之间的圆角和间隙
- Python检查ping终端
- HTTP请求首部的Host字段
- 初学unity,以后做一些笔记
- Required method destroyItem was not overridden
- Socket(二)基于InputStream和OutputStream实现多人聊天功能
- 对JAVA强引用、软引用、弱引用、虚引用的理解
- scala建议使用常量val,而不使用变量var
- HNUST 1695: 跳格子(简单模拟)
- CSS清除浮动方法及优缺点分析
- Fragment结合ViewPager之懒加载 1
- Hibernate单条查询语句get/load方法区别
- 使用Object对象的toString()方法自定义判断数据类型方法
- 如何关闭TestFlight beta测试