• Java-在线聊天系统-线程


    一、概述

    1.目标:在上一个版本非线程的聊天系统中,出于要不断监听接收新client和接收client发出的信息,把accept()和DataInputStream.readUTF()分别写在了while()死循环里,由于俩方法都是阻塞性方法,所以一方阻塞,另一方永远得不到执行,所以,在上述代码中,只能监听第一个client的发送信息,新的client永远连接不上。

    2.思路:

    (1)把socet.accept()接收线程和DataInputStream.readUTF()的处理分开,把前者交给server端的处理,server端把接收到的clent封装到线程里,把DataInputStream.readUTF()的逻辑交给线程处理。

    (2)采用异步IO

    二、代码

    1.ChatServer.java

    import java.io.DataInputStream;
    import java.io.EOFException;
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    
    public class ChatServer{
    	
    	private ServerSocket ss = null;
    	private boolean started = false;
    	
    	public static void main(String[] args) {
    		new ChatServer().start();
    	}
    
    	
    	public void start(){
    		
    		try {
    			ss = new ServerSocket(8888);
    			started = true;
    		} catch (IOException e1) {
    			e1.printStackTrace();
    		}
    		
    		try {
    			while(started){
    				//!!!!!注意accept()是阻塞性方法,当被readUTF()阻塞时它不会被执行
    				Socket s = ss.accept();
    System.out.println("a client connect------"+s);
    				new Thread(new Client(s)).start();
    			}
    		} catch (EOFException e) {
    			System.out.println("客户端已关闭!");
    		} catch (IOException e) {
    			e.printStackTrace();
    		}finally{
    			try {
    				//if(dis != null ) dis.close();
    				//if(s != null ) s.close();
    				if(ss != null ) ss.close();
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	
    	private class Client implements Runnable{
    		
    		private Socket s;
    		private DataInputStream dis = null;
    		boolean bConnect = false;
    		
    		public Client(Socket s) {
    			super();
    			this.s = s;
    			try {
    				dis = new DataInputStream(s.getInputStream());
    				bConnect = true;
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    
    
    		@Override
    		public void run() {
    				try {
    					while(bConnect){
    					//!!!!!注意readUTF()是阻塞性方法
    					System.out.println(dis.readUTF());
    					}
    				} catch (EOFException e) {
    		            System.out.println("客户端已关闭!");
    		        } 
    				catch (IOException e) {
    					e.printStackTrace();
    				}finally{
    					try {
    						if(dis != null ) dis.close();
    						if(s != null ) s.close();
    					} catch (Exception e) {
    						e.printStackTrace();
    					}
    				}
    			}
    		}
    		
    
    }
    

      

    2.ChatClient.java

    import java.awt.BorderLayout;
    import java.awt.Button;
    import java.awt.Frame;
    import java.awt.TextArea;
    import java.awt.TextField;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.KeyEvent;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.io.OutputStream;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    
    public class ChatClient extends Frame{
    
    	private TextField tfText;
    	private TextArea taContent;
    //	private Button btnSend;
    	private Socket socket;
    	private DataOutputStream dos;
    	
    	public void launchFrame(){
    		
    		addWindowListener(new WindowAdapter() {
    			 public void windowClosing(WindowEvent e) {
    				 disconnect();
    				 System.exit(0);
    			 }
    		});
    		
    		tfText = new TextField();
    		taContent = new TextArea();
    //		btnSend = new Button("发送");
    //		
    //		btnSend.addActionListener(new ActionListener() {
    //			@Override
    //			public void actionPerformed(ActionEvent e) {
    //				//taContent.setText(taContent.getText()+"
    
    "+tfText.getText());
    //				//tfText.setText("");
    //				try {
    //					DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
    //					dos.writeUTF(tfText.getText());
    //					dos.close();
    //					socket.close();
    //				} catch (IOException e1) {
    //					e1.printStackTrace();
    //				}
    //			}
    //		});
    		
    		tfText.addActionListener(new TFListener());
    		
    		add(taContent,BorderLayout.NORTH);
    		add(tfText,BorderLayout.CENTER);
    //		add(btnSend,BorderLayout.SOUTH);
    		setLocation(300, 100);
    		pack();
    		setVisible(true);
    		connect("localhost", 8888);
    	}
    	
    	//当调用了此方法,会自动把成员变量给socket连接上server
    	public void  connect(String address, int port){
    		try {
    			socket = new Socket(address, port);
    			dos = new DataOutputStream(socket.getOutputStream());
    		} catch (UnknownHostException e) {
    			e.printStackTrace();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	//退出时释放资源
    	public void disconnect(){
    		try {
    			if(dos != null ) dos.close();
    			if(socket != null ) socket.close();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    	}
    	
    	class TFListener implements ActionListener{
    
    		@Override
    		public void actionPerformed(ActionEvent e) {
    			taContent.setText(taContent.getText().trim()+"
    
    "+tfText.getText());
    			
    			try {
    				dos.writeUTF(tfText.getText());
    				dos.flush();
    				tfText.setText("");
    				//dos.close();
    				//socket.close();
    			} catch (IOException e1) {
    				e1.printStackTrace();
    			}
    		}
    	}
    	
    	public static void main(String[] args) {
    		new ChatClient().launchFrame();
    	}
    }
    

      

    三、运行结果

  • 相关阅读:
    ES6 新属性 Symbol
    box-shadow 属性详解
    在vue 中 使用 tinymce编辑器
    var let const 结合作用域 的探讨
    防抖和节流在vue中的应用
    分享几个按钮样式
    队列学习
    栈的学习
    Object—常用的遍历
    从零认识Java Package
  • 原文地址:https://www.cnblogs.com/shamgod/p/4612142.html
Copyright © 2020-2023  润新知