zoukankan      html  css  js  c++  java
  • JavaSE项目之聊天室swing版

    引子:

    当前,互联网 体系结构的参考模型主要有两种,一种是OSI参考模型,另一种是TCP/IP参考模型。

    一、OSI参考模型,即开放式通信系统互联参考模型(OSI/RM,Open Systems Interconnection Reference Model),是国际标准化组织(ISO)提出的一个试图使各种计算机在世界范围内互连为网络的标准框架,简称OSI。 

    OSI参考模型将实现网络互连的通信协议分为7层,自上而下分别是:

    第7层应用层:OSI中的最高层,为用户提供各项互联网应用,如公司老板通过浏览器上网、发送电子邮件等。 常见的协议有:HTTP,HTTPS,FTP,TELNET,SSH,SMTP,POP3等。

    第6层表示层:相当公司中替老板写信的助理。

    第5层会话层:相当于公司中收寄信、写信封与拆信封的秘书。

    第4层传输层:提供终端到终端的可靠连接,相当于公司中跑邮局的送信职员。

    第3层网络层: 确保信件通过一系列路由到达目的地。

    第2层数据链路层: 决定访问网络介质的方式,并处理流控制。

    第1层物理层:处于OSI参考模型的最底层,物理层的主要功能是利用物理传输介质为数据链路层提供物理连接,以便透明地传输比特流;该层的常用设备有网卡、集线器、中继器、调制解调器、网线、双绞线、同轴电缆等各种物理设备。

    数据发送时,从第七层传到第一层,接收数据则相反。

    上三层总称为“应用层”,用来控制软件方面;下四层总称为“数据流层”,用来管理硬件。除了物理层之外,其他层都是用软件实现的。

    二、TCP/IP参考模型。

    第四层应用层:协议有DNS、FTP、HTTP、HTTPS、Telnet、SMTP等;

    第三层传输层:TCP、UDP等;

    第二层网际层: IP、ICMP等;

    第一层网络接口层:ARP、RARP等。

    我们在对上述两种参考模型有些了解后,接下来主要看TCP和UDP。我们先来看二者的区别:

    1.TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接;

    2.TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付;

    3.TCP面向字节流,实际上是TCP把数据看成是一连串无结构的字节流;UDP是面向报文的,它没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(如IP电话,实时视频会议等)

    4.每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信;

    5.TCP首部开销20字节;UDP的首部开销小,只有8个字节;

    6.TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。

    在Java中,对遵守TCP协议的类有ServerSocket和Socket,遵守UDP协议的类有DatagramSocket。我这里提供的聊天室项目,是基于TCP协议的。

    该项目分为4个包,分别是utils(提供工具),ui(提供窗体界面),server(服务器子线程),client(客户端子线程)。项目文件包结构如下图所示:

    项目运行后的效果如下图所示:

    接下来是项目代码:

    package 聊天室swing版.utils;
    /**
     * 工具类,服务器ip,端口等信息
     */
    import java.net.InetAddress;
    import java.net.UnknownHostException;
    public abstract class HostInfo {
    	public static  String IP=getIP();
    	public static final int PORT=10086;
    	public static final int NUM=50;
    	public static final String NEW_LINE="
    ";
    	private static String getIP(){
    		try {
    			return InetAddress.getLocalHost().getHostAddress();
    		} catch (UnknownHostException e) {
    			e.printStackTrace();
    			return null;
    		}
    	}
    }
    -----------------------------------------------------------
    package 聊天室swing版.utils;
    /**
     * 工具类,释放资源
     */
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    public abstract class Release {
    	public static void release(Socket socket,BufferedWriter bw){
    		release(null,socket,null,bw);
    	}
    	public static void release(Socket socket,BufferedReader br){
    		release(null,socket,br,null);
    	}
    	public static void release(Socket socket){
    		release(null,socket,null,null);
    	}
    	public static void release(ServerSocket server){
    		release(server,null,null,null);
    	}
    	public static void release(ServerSocket server,Socket socket,BufferedReader br,BufferedWriter bw){
    		if(server!=null){
    			try {
    				server.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		if(socket!=null){
    			try {
    				socket.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		if(br!=null){
    			try {
    				br.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		if(bw!=null){
    			try {
    				bw.close();
    			} catch (IOException e) {
    				e.printStackTrace();
    			}
    		}
    		
    	}
    }
    -----------------------------------------------------------------
    package 聊天室swing版.server;
    /**
     * 服务器Server类
     */
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.ArrayList;
    import java.util.List;
    
    import 聊天室swing版.ui.UIserver;
    import 聊天室swing版.utils.HostInfo;
    import 聊天室swing版.utils.Release;
    public class Server extends Thread {
    	private ServerSocket server;
    	public static List<Transport> clients=new ArrayList<>();
    	@Override
    	public void run() {
    		try {
    			server=new ServerSocket(Integer.parseInt(UIserver.jtf_port.getText().trim()));
    		} catch (IOException e) {
    			Release.release(server);
    			throw new RuntimeException("服务器端口被占!");
    		}
    		UIserver.bt_open.setText("已启动服务器");
    		UIserver.bt_open.setEnabled(false);
    		UIserver.jta_log.append("服务器成功启动!"+HostInfo.NEW_LINE);
    		new Accept().start();
    	}
    	class Accept extends Thread{
    		private Socket socket;
    		@Override
    		public void run() {
    			int num=0;
    			while(num<HostInfo.NUM){
    				try {
    					socket=server.accept();
    				} catch (IOException e) {
    					Release.release(socket);
    					throw new RuntimeException("客户端连接失败!");
    				}
    				num++;
    				String str="第 "+num+" 个客户端连接成功!==>"+socket.getInetAddress().getHostAddress()+" :"+socket.getPort()+HostInfo.NEW_LINE;
    				UIserver.jta_log.append(str);
    				clients.add(new Transport(socket));
    			}
    			UIserver.jta_log.append("超出服务器负荷!");
    			Release.release(server);
    		}
    	}
    }
    ----------------------------------------------------
    package 聊天室swing版.server;
    /**
     * 处理服务器Server类中接收客户端发来的信息,以及转发客户端发来的信息
     */
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.net.Socket;
    
    import 聊天室swing版.utils.Release;
    public class Transport extends Thread {
    	private Socket socket;
    	private String ip;
    	public Transport(Socket socket){
    		this.socket=socket;
    		this.ip=socket.getInetAddress().getHostAddress();
    		this.start();
    	}
    	@Override
    	public void run() {
    		BufferedReader br=null;
    		BufferedWriter ownbw=null;
    		try {
    			br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
    			ownbw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    		} catch (IOException e) {
    			Server.clients.remove(this);
    			Release.release(socket);
    			throw new RuntimeException("获取流失败!");
    		}
    		String str=null;
    		try {
    			while((str=br.readLine())!=null){
    				String[] split = str.split(":", 2);
    				if(split.length<=1){
    					ownbw.write("数据格式错误!");
    					ownbw.newLine();
    					ownbw.flush();
    				}
    				String desip=split[0];
    				String content=split[1];
    				BufferedWriter desbw=null;
    				boolean isOnLine=false;
    				for(Transport des:Server.clients){
    					if(desip.equals(des.ip)){
    						isOnLine=true;
    						desbw=new BufferedWriter(new OutputStreamWriter(des.socket.getOutputStream()));
    						desbw.write(str);
    						desbw.newLine();
    						desbw.flush();
    					}
    				}
    				if(!isOnLine){
    					ownbw.write("对方不在线!");
    					ownbw.newLine();
    					ownbw.flush();
    				}
    			}
    		} catch (IOException e) {
    			Server.clients.remove(this);
    			Release.release(socket);
    			throw new RuntimeException("获取流失败!");
    		}
    	}
    }
    ------------------------------------------------------------
    package 聊天室swing版.client;
    /**
     * 客户端类,向服务器发送信息,以及接收服务器发来的信息
     */
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.net.Socket;
    
    import 聊天室swing版.ui.UIclient;
    import 聊天室swing版.ui.UIserver;
    import 聊天室swing版.utils.HostInfo;
    import 聊天室swing版.utils.Release;
    public class Client extends Thread {
    	private Socket socket;
    	@Override
    	public void run() {
    		try {
    			socket=new Socket(UIserver.jtf_ip.getText().toLowerCase(), Integer.parseInt(UIserver.jtf_port.getText().trim()));
    		}  catch (IOException e) {
    			Release.release(socket);
    			throw new RuntimeException("客户端创建失败!");
    		}
    		BufferedReader br=null;
    		try {
    			br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
    		} catch (IOException e) {
    			Release.release(socket);
    			throw new RuntimeException("获取流失败!");
    		}
    		String str=null;
    		try {
    			while((str=br.readLine())!=null){
    				UIclient.jta_chat.append(str+HostInfo.NEW_LINE);
    			}
    		} catch (IOException e) {
    			Release.release(socket);
    			throw new RuntimeException("获取流失败!");
    		}
    	}
    	public void send(){
    		new Send().start();
    	}
    	class Send extends Thread{
    		@Override
    		public void run() {
    			BufferedWriter bw=null;
    			try {
    				bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    			} catch (IOException e) {
    				Release.release(socket,bw);
    				throw new RuntimeException("获取流失败!");
    			}
    			String str=UIclient.jtf_desip.getText().trim()+":"+UIclient.jta_message.getText().trim();
    			try {
    				bw.write(str);
    				bw.newLine();
    				bw.flush();
    			} catch (IOException e) {
    				Release.release(socket,bw);
    				throw new RuntimeException("获取流失败!");
    			}
    		}
    	}
    }
    -------------------------------------------------------------
    package 聊天室swing版.ui;
    /**
     * 服务器端UI
     * 要先开启服务器,再开启客户端
     */
    import java.awt.Dimension;
    import java.awt.FlowLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    
    import 聊天室swing版.server.Server;
    import 聊天室swing版.utils.HostInfo;
    public class UIserver extends JFrame {
    	private JPanel jp=new JPanel();
    	private JLabel jl_ipTips=new JLabel("服务器ip:");
    	public static JTextField jtf_ip=new JTextField(HostInfo.IP);
    	private JLabel jl_portTips=new JLabel("服务器端口:");
    	public static JTextField jtf_port=new JTextField(HostInfo.PORT+"");
    	public static JButton bt_open=new JButton("启动服务器");
    	public static JTextArea jta_log=new JTextArea();
    	private JScrollPane jsp_log=new JScrollPane(jta_log);
    	public UIserver(){
    		jp.setLayout(new FlowLayout());
    		jp.add(jl_ipTips);
    		jp.add(jtf_ip);
    		jp.add(jl_portTips);
    		jp.add(jtf_port);
    		jp.add(bt_open);
    		jp.add(jsp_log);
    		jl_ipTips.setPreferredSize(new Dimension(100, 50));
    		jtf_ip.setPreferredSize(new Dimension(150, 50));
    		jl_portTips.setPreferredSize(new Dimension(100, 50));
    		jtf_port.setPreferredSize(new Dimension(150, 50));
    		bt_open.setPreferredSize(new Dimension(260, 50));
    		jsp_log.setPreferredSize(new Dimension(260, 192));
    		jta_log.setLineWrap(true);
    		jta_log.setEditable(false);
    		bt_open.addActionListener(new ActionListener(){
    			@Override
    			public void actionPerformed(ActionEvent arg0) {
    				new Server().start();
    			}
    		});
    		add(jp);
    		setTitle("聊天应用控制服务器");
    		setBounds(100, 50, 300, 400);
    		setResizable(false);
    		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		setVisible(true);
    	}
    	public static void main(String[] args) {
    		new UIserver();
    	}
    }
    ---------------------------------------------------------------
    package 聊天室swing版.ui;
    /**
     * 客户端UI
     */
    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.event.FocusAdapter;
    import java.awt.event.FocusEvent;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    
    import 聊天室swing版.client.Client;
    public class UIclient extends JFrame {
    	private JPanel jp_chat=new JPanel();
    	public static JTextArea jta_chat=new JTextArea();
    	private JScrollPane jsp_chat=new JScrollPane(jta_chat);
    	private JPanel jp_send=new JPanel();
    	public static  JTextField jtf_desip=new JTextField("请输入对方Ip");
    	public static  JTextArea jta_message=new JTextArea();
    	private JScrollPane jsp_message=new JScrollPane(jta_message);
    	private JButton bt_send=new JButton("发送");
    	private Client client;
    	public UIclient(){
    		jp_chat.add(jsp_chat);
    		jta_chat.setLineWrap(true);
    		jta_chat.setEditable(false);
    		jsp_chat.setPreferredSize(new Dimension(550, 400));
    		jp_send.add(jtf_desip);
    		jp_send.add(jsp_message);
    		jta_message.setLineWrap(true);
    		jp_send.add(bt_send);
    		jtf_desip.setPreferredSize(new Dimension(100, 50));		
    		jsp_message.setPreferredSize(new Dimension(250, 50));
    		bt_send.setPreferredSize(new Dimension(100, 50));
    		jtf_desip.addFocusListener(new FocusAdapter(){
    		@Override
    		public void focusGained(FocusEvent e) {
    			jtf_desip.setText("");
    			}
    		});
    		jta_message.addFocusListener(new FocusAdapter(){
    			@Override
    			public void focusGained(FocusEvent e) {
    				jta_message.setText("");
    			}
    		});
    		bt_send.addActionListener(new ActionListener(){
    
    			@Override
    			public void actionPerformed(ActionEvent arg0) {
    				client.send();
    			}
    		});
    		add(jp_chat, BorderLayout.CENTER);
    		add(jp_send, BorderLayout.SOUTH);
    		setTitle("群聊窗口");
    		setBounds(300, 100, 600, 500);
    		setResizable(false);
    		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    		setVisible(true);
    		client=new Client();
    		client.start();
    	}
    	public static void main(String[] args) {
    		new UIclient();
    	}
    }
    

      您可以在Eclipse上运行下,如果有问题,欢迎留言。希望对您有所帮助!

  • 相关阅读:
    开源的Linux QQ
    如何从VS2003升级到VS2008
    LINQ在开发中的地位?
    SQL Server 2005 Analysis Services
    .NET framework源代码开放了
    WebForms和MVC这2个模型都很棒,由相关讨论想到的
    IIS 7.0相关文章收集
    探究基于声明的身份标识
    微软为“离线”做好准备:推出同步框架
    通用日志
  • 原文地址:https://www.cnblogs.com/lizhangyong/p/8137686.html
Copyright © 2011-2022 走看看