引子:

当前,互联网 体系结构的参考模型主要有两种,一种是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项目之聊天室的更多相关文章

  1. JavaSE项目之聊天室swing版

    引子: 当前,互联网 体系结构的参考模型主要有两种,一种是OSI参考模型,另一种是TCP/IP参考模型. 一.OSI参考模型,即开放式通信系统互联参考模型(OSI/RM,Open Systems In ...

  2. Django项目--web聊天室

    需求 做一个web聊天室,主要练习前端ajax与后台的交互: 一对一聊天和群组聊天 添加用户为好友 搜索并添加群组 管理员可以审批用户加群请求,群管理员可以有多个,群管理员可以删除,添加禁言群友 与聊 ...

  3. 小项目:聊天室 (jQuery,PHP,MySQL)

    这几天写了一个小项目,初衷是自己写一个有前端,有后端的东西练练手,所以,实际意义并不大,只是拿来试试手而已. 我对这个聊天室的构想是这样的:先建两个数据库,一个保存用户名和密码,另一个保存用户名和发送 ...

  4. 聊天室(下篇)GatewayWorker 与 Laravel 的整合

    思路 上一篇大概梳理了一下 GatewayWorker 的基础知识.这篇就来准备整合 GatewayWorker 到 Laravel. GatewayWorker 是基于 Socket 监听的服务器框 ...

  5. Linux聊天室项目 -- ChatRome(select实现)

    序 项目简介:采用I/O复用技术select实现socket通信,采用多线程负责每个客户操作处理,完成Linux下的多客户聊天室! OS:Ubuntu 15.04 IDE:vim gcc make D ...

  6. 基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍。最后我们将会实现一个基于Server-Sent Event和Flask简单的在线聊天室。

    基于Server-Sent Event的简单聊天室 Web 2.0时代,即时通信已经成为必不可少的网站功能,那实现Web即时通信的机制有哪些呢?在这门项目课中我们将一一介绍.最后我们将会实现一个基于S ...

  7. 《基于Node.js实现简易聊天室系列之项目前期工作》

    前期工作主要包括:项目的创建,web服务器的创建和数据库的连接. 项目创建 网上关于Node.js项目的创建的教程有很多,这里不必赘述.Demo所使用的Node.js的框架是express,版本为4. ...

  8. 学习JavaSE TCP/IP协议与搭建简易聊天室

    一.TCP/IP协议 1.TCP/IP协议包括TCP.IP和UDP等 2.域名通过dns服务器转换为IP地址 3.局域网可以通过IP或者主机地址寻找到相应的主机 4.TCP是可靠的连接,效率低,且连接 ...

  9. Asp.NET MVC 使用 SignalR 实现推送功能二(Hubs 在线聊天室 获取保存用户信息)

    简单介绍 关于SignalR的简单实用 请参考 Asp.NET MVC 使用 SignalR 实现推送功能一(Hubs 在线聊天室) 在上一篇中,我们只是介绍了简单的消息推送,今天我们来修改一下,实现 ...

随机推荐

  1. 用TensorFlow实现文本分析模型,做个聊天机器人

    用TensorFlow实现文本分析模型,做个聊天机器人 聊天机器人的架构简图用 TensorFlow 实现 Chatbot 的模型如何准备 chatbot 的训练数据Chatbot 源码解读 1. 聊 ...

  2. APP加固技术历程及未来级别方案:虚机源码保护

    传统App加固技术,前后经历了四代技术变更,保护级别每一代都有所提升,但其固有的安全缺陷和兼容性问题始终未能得到解决.而下一代加固技术-虚机源码保护,适用代码类型更广泛,App保护级别更高,兼容性更强 ...

  3. 深入了解Android蓝牙Bluetooth——《基础篇》

    什么是蓝牙?   也可以说是蓝牙技术.所谓蓝牙(Bluetooth)技术,实际上是一种短距离无线电技术,是由爱立信公司公司发明的.利用"蓝牙"技术,能够有效地简化掌上电脑.笔记本电 ...

  4. Java语句语法

    一.流程控制语句 1.分支语句 1)if else 语法:(写法1) if(条件1){     //写一次 满足条件1执行在代码 }else if(条件2){    //写0或n次 不满足条件1,满足 ...

  5. openstack pike与ceph集成

    openstack pike与ceph集成 Ceph luminous 安装配置 http://www.cnblogs.com/elvi/p/7897178.html openstack pike 集 ...

  6. JavaScript OOP(三):prototype原型对象(即构造函数的prototype属性)

    通过构造函数生成的实例化对象,无法共享属性或方法(即每个实例化对象上都有构造函数中的属性和方法):造成了一定的资源浪费 function Obj(name,age){ this.name=name; ...

  7. java的基本知识导航

    java基本知识 备注:本次主要是思维导图,就是简单的说一下,只会扩展导图中的java关键字,其他以后再写 1.思维导图 2.java关键字 关键字 描述  abstract 抽象方法,抽象类的修饰符 ...

  8. Linux服务器制定mysql数据库备份的计划任务

    首先,创建一个shell脚本: Shell #!/bin/bash mysql_pwd="1234567890" mysql_dump="/usr/local/mysql ...

  9. Python的字典

    1.  Python的字典 1.1.  字典的定义 在Python中,字典是一种key-value的数据类型,也是唯一的映射类型:字典还是另一种可变容器类型,且可存储任意类型对象,其中也可包括其他容器 ...

  10. c++简单编写线性表(实验)

    哇 好久没更博客了  因为从上次更文到现在为止,我一直在学c#,然后也觉得没什么太大的东西想写在博客上, 总之这次就简单的传一下学校安排的数据结构的实验,我还是学生,是新手,希望能继续跟大家一起学习, ...