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="\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;
/**
* 服务器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上运行下,如果有问题,欢迎留言。希望对您有所帮助!
JavaSE项目之聊天室swing版的更多相关文章
- JavaSE项目之聊天室
引子: 当前,互联网 体系结构的参考模型主要有两种,一种是OSI参考模型,另一种是TCP/IP参考模型. 一.OSI参考模型,即开放式通信系统互联参考模型(OSI/RM,Open Systems In ...
- 基于TCP协议的聊天室控制台版
我之前写过一篇博客,主要是基于TCP协议实现的聊天室swing版,在此再写一个基于TCP协议实现的聊天室控制台版,便于学习和比较. package 聊天室console版.utils; import ...
- Django项目--web聊天室
需求 做一个web聊天室,主要练习前端ajax与后台的交互: 一对一聊天和群组聊天 添加用户为好友 搜索并添加群组 管理员可以审批用户加群请求,群管理员可以有多个,群管理员可以删除,添加禁言群友 与聊 ...
- 小项目:聊天室 (jQuery,PHP,MySQL)
这几天写了一个小项目,初衷是自己写一个有前端,有后端的东西练练手,所以,实际意义并不大,只是拿来试试手而已. 我对这个聊天室的构想是这样的:先建两个数据库,一个保存用户名和密码,另一个保存用户名和发送 ...
- react-native聊天室|RN版聊天App仿微信实例|RN仿微信界面
一.前言 9月,又到开学的季节.为每个一直默默努力的自己点赞!最近都沉浸在react native原生app开发中,之前也有使用vue/react/angular等技术开发过聊天室项目,另外还使用RN ...
- go 聊天室简单版总结
/* * 思路:在登录成功时将用户的id存进在线用户列表中的key value中链接的ws为空,并保存用户的信息. * 当跳转到聊天室时,将用户和聊天室链接的ws存进在线用户列表中的 * 问题:如何在 ...
- 简单聊天室(java版)
这是本人从其他地方学习到的关于聊天室的一个模本,我从中截取了一部分关于客户端和服务端通信的Socket的内容.希望对大家对socket有个了解,我写的这些代码可以实现两人或多人在多台电脑上实现简单的对 ...
- 聊天室(下篇)GatewayWorker 与 Laravel 的整合
思路 上一篇大概梳理了一下 GatewayWorker 的基础知识.这篇就来准备整合 GatewayWorker 到 Laravel. GatewayWorker 是基于 Socket 监听的服务器框 ...
- 第一节:.Net版基于WebSocket的聊天室样例
一. 说在前面的话 该篇文章为实时通讯系列的第一节,基于WebSocket编写了一个简易版聊天样例,主要作用是为引出后面SignalR系列的用法及其强大方便之处,通过这个样例与后续的SignalR对比 ...
随机推荐
- CentOS 不间断会话(ssh关闭后如何保证程序继续运行)(nohup和screen)
当使用ssh与远程主机的会话被关闭时,在远程主机上运行的命令也随之被中断. 就是ssh 打开以后,bash等都是他的子程序,一旦ssh关闭,系统将所有相关进程杀掉!! 导致一旦ssh关闭,执行中的任务 ...
- POJ3581:Sequence——题解
http://poj.org/problem?id=3581 给一串数,将其分成三个区间并且颠倒这三个区间,使得新数列字典序最小. 参考:http://blog.csdn.net/libin56842 ...
- PHP 数据库防止攻击
定义和用法 mysql_real_escape_string() 函数转义 SQL 语句中使用的字符串中的特殊字符. 下列字符受影响: \x00 \n \r \ ' " \x1a 如果成功, ...
- MongoDB基操
基本概念 database 数据库 包含多个collection collection 集合 包含多个文档document(类JSON对象) document 文档 一个文档对象中包含多个key-va ...
- ACE反应器(Reactor)模式(3)
转载于:http://www.cnblogs.com/TianFang/archive/2006/12/18/595938.html 在服务器端使用Reactor框架 使用Reactor框架的服务器端 ...
- jq 由name获取那个radio选中了的
$("input[name='approve']:checked").val() //获取radio选中的值;var radio_checked_val = $("#fo ...
- 解决Sublime Install Package的There are no packages available for install问题(channel_v3.json)
Sublime版本 Sublime Text 3.1.1 Build 3176 自己也尝试了很多次,所以这一解决办法仅是可能解决你的问题 一.解决简要描述 造成的原因大致是 无法通过request去获 ...
- 51Nod 1062 序列中最大的数 | 简单DP
#include "iostream" #include "cstdio" using namespace std; #define LL long long ...
- BZOJ2733:使用并查集维护连通性之后用线段树维护+线段树合并(动态开点)
可以说是线段树合并的裸题吧 题意就是给你两个操作 一个操作是合并两个集合,这两个集合都是用权值线段树维护的,便于查询第k小元素 另一个操作就是查询区间极值了 #include<cstdio> ...
- VirtualBox4.3.12 安装ubuntu 14.04 分辨率过小(600*480)问题的解决方法
作为.net程序员,一直都跟windows系统打交道,在同事的影响下,今天安装了Ubuntu 14. 安装完系统就遇到了这个麻烦事,找了好久才解决,因此记录下来,或许对和我一样的Ubuntu新手有帮助 ...