JavaSE项目之聊天室swing版
引子:
當(dāng)前,互聯(lián)網(wǎng) 體系結(jié)構(gòu)的參考模型主要有兩種,一種是OSI參考模型,另一種是TCP/IP參考模型。
一、OSI參考模型,即開(kāi)放式通信系統(tǒng)互聯(lián)參考模型(OSI/RM,Open Systems Interconnection Reference Model),是國(guó)際標(biāo)準(zhǔn)化組織(ISO)提出的一個(gè)試圖使各種計(jì)算機(jī)在世界范圍內(nèi)互連為網(wǎng)絡(luò)的標(biāo)準(zhǔn)框架,簡(jiǎn)稱OSI。?
OSI參考模型將實(shí)現(xiàn)網(wǎng)絡(luò)互連的通信協(xié)議分為7層,自上而下分別是:
第7層應(yīng)用層:OSI中的最高層,為用戶提供各項(xiàng)互聯(lián)網(wǎng)應(yīng)用,如公司老板通過(guò)瀏覽器上網(wǎng)、發(fā)送電子郵件等。 常見(jiàn)的協(xié)議有:HTTP,HTTPS,FTP,TELNET,SSH,SMTP,POP3等。
第6層表示層:相當(dāng)公司中替老板寫(xiě)信的助理。
第5層會(huì)話層:相當(dāng)于公司中收寄信、寫(xiě)信封與拆信封的秘書(shū)。
第4層傳輸層:提供終端到終端的可靠連接,相當(dāng)于公司中跑郵局的送信職員。
第3層網(wǎng)絡(luò)層: 確保信件通過(guò)一系列路由到達(dá)目的地。
第2層數(shù)據(jù)鏈路層: 決定訪問(wèn)網(wǎng)絡(luò)介質(zhì)的方式,并處理流控制。
第1層物理層:處于OSI參考模型的最底層,物理層的主要功能是利用物理傳輸介質(zhì)為數(shù)據(jù)鏈路層提供物理連接,以便透明地傳輸比特流;該層的常用設(shè)備有網(wǎng)卡、集線器、中繼器、調(diào)制解調(diào)器、網(wǎng)線、雙絞線、同軸電纜等各種物理設(shè)備。
數(shù)據(jù)發(fā)送時(shí),從第七層傳到第一層,接收數(shù)據(jù)則相反。
上三層總稱為“應(yīng)用層”,用來(lái)控制軟件方面;下四層總稱為“數(shù)據(jù)流層”,用來(lái)管理硬件。除了物理層之外,其他層都是用軟件實(shí)現(xiàn)的。
二、TCP/IP參考模型。
第四層應(yīng)用層:協(xié)議有DNS、FTP、HTTP、HTTPS、Telnet、SMTP等;
第三層傳輸層:TCP、UDP等;
第二層網(wǎng)際層: IP、ICMP等;
第一層網(wǎng)絡(luò)接口層:ARP、RARP等。
我們?cè)趯?duì)上述兩種參考模型有些了解后,接下來(lái)主要看TCP和UDP。我們先來(lái)看二者的區(qū)別:
1.TCP面向連接(如打電話要先撥號(hào)建立連接);UDP是無(wú)連接的,即發(fā)送數(shù)據(jù)之前不需要建立連接;
2.TCP提供可靠的服務(wù)。也就是說(shuō),通過(guò)TCP連接傳送的數(shù)據(jù),無(wú)差錯(cuò),不丟失,不重復(fù),且按序到達(dá);UDP盡最大努力交付,即不保證可靠交付;
3.TCP面向字節(jié)流,實(shí)際上是TCP把數(shù)據(jù)看成是一連串無(wú)結(jié)構(gòu)的字節(jié)流;UDP是面向報(bào)文的,它沒(méi)有擁塞控制,因此網(wǎng)絡(luò)出現(xiàn)擁塞不會(huì)使源主機(jī)的發(fā)送速率降低(如IP電話,實(shí)時(shí)視頻會(huì)議等)
4.每一條TCP連接只能是點(diǎn)到點(diǎn)的;UDP支持一對(duì)一,一對(duì)多,多對(duì)一和多對(duì)多的交互通信;
5.TCP首部開(kāi)銷20字節(jié);UDP的首部開(kāi)銷小,只有8個(gè)字節(jié);
6.TCP的邏輯通信信道是全雙工的可靠信道,UDP則是不可靠信道。
在Java中,對(duì)遵守TCP協(xié)議的類有ServerSocket和Socket,遵守UDP協(xié)議的類有DatagramSocket。我這里提供的聊天室項(xiàng)目,是基于TCP協(xié)議的。
該項(xiàng)目分為4個(gè)包,分別是utils(提供工具),ui(提供窗體界面),server(服務(wù)器子線程),client(客戶端子線程)。項(xiàng)目文件包結(jié)構(gòu)如下圖所示:
項(xiàng)目運(yùn)行后的效果如下圖所示:
接下來(lái)是項(xiàng)目代碼:
package 聊天室swing版.utils; /*** 工具類,服務(wù)器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="\r\n";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; /*** 服務(wù)器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<>();@Overridepublic void run() {try {server=new ServerSocket(Integer.parseInt(UIserver.jtf_port.getText().trim()));} catch (IOException e) {Release.release(server);throw new RuntimeException("服務(wù)器端口被占!");}UIserver.bt_open.setText("已啟動(dòng)服務(wù)器");UIserver.bt_open.setEnabled(false);UIserver.jta_log.append("服務(wù)器成功啟動(dòng)!"+HostInfo.NEW_LINE);new Accept().start();}class Accept extends Thread{private Socket socket;@Overridepublic 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+" 個(gè)客戶端連接成功!==>"+socket.getInetAddress().getHostAddress()+" :"+socket.getPort()+HostInfo.NEW_LINE;UIserver.jta_log.append(str);clients.add(new Transport(socket));}UIserver.jta_log.append("超出服務(wù)器負(fù)荷!");Release.release(server);}} } ---------------------------------------------------- package 聊天室swing版.server; /*** 處理服務(wù)器Server類中接收客戶端發(fā)來(lái)的信息,以及轉(zhuǎn)發(fā)客戶端發(fā)來(lái)的信息*/ 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();}@Overridepublic 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("數(shù)據(jù)格式錯(cuò)誤!");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("對(duì)方不在線!");ownbw.newLine();ownbw.flush();}}} catch (IOException e) {Server.clients.remove(this);Release.release(socket);throw new RuntimeException("獲取流失敗!");}} } ------------------------------------------------------------ package 聊天室swing版.client; /*** 客戶端類,向服務(wù)器發(fā)送信息,以及接收服務(wù)器發(fā)來(lái)的信息*/ 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;@Overridepublic 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("客戶端創(chuàng)建失敗!");}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{@Overridepublic 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; /*** 服務(wù)器端UI* 要先開(kāi)啟服務(wù)器,再開(kāi)啟客戶端*/ 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("服務(wù)器ip:");public static JTextField jtf_ip=new JTextField(HostInfo.IP);private JLabel jl_portTips=new JLabel("服務(wù)器端口:");public static JTextField jtf_port=new JTextField(HostInfo.PORT+"");public static JButton bt_open=new JButton("啟動(dòng)服務(wù)器");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(){@Overridepublic void actionPerformed(ActionEvent arg0) {new Server().start();}});add(jp);setTitle("聊天應(yīng)用控制服務(wù)器");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("請(qǐng)輸入對(duì)方Ip");public static JTextArea jta_message=new JTextArea();private JScrollPane jsp_message=new JScrollPane(jta_message);private JButton bt_send=new JButton("發(fā)送");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(){@Overridepublic void focusGained(FocusEvent e) {jtf_desip.setText("");}});jta_message.addFocusListener(new FocusAdapter(){@Overridepublic void focusGained(FocusEvent e) {jta_message.setText("");}});bt_send.addActionListener(new ActionListener(){@Overridepublic 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上運(yùn)行下,如果有問(wèn)題,歡迎留言。希望對(duì)您有所幫助!
轉(zhuǎn)載于:https://www.cnblogs.com/lizhangyong/p/8137686.html
總結(jié)
以上是生活随笔為你收集整理的JavaSE项目之聊天室swing版的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: android,面向对象
- 下一篇: Java方法的静态绑定与动态绑定讲解