java在线聊天项目1.0版 异常处理——开启多个客户端,关闭一个客户端后,在其他客户端中再发出信息会出现异常的处理
异常一
只开启一个客户端,输入信息后关闭,客户端出现如下异常

根据异常说明 ChatClientFrame客户端117行
提示原因是Socket关闭
分析原因
客户端代码
while (connected) {
String str = dis.readUTF();
当窗口关闭后,Socket已经关闭,读的操作还在继续
处理这个异常,代码如下
catch (SocketException e) {
System.out.println("a client has been closed!");
}
同时,
服务端出现下边异常

解决异常
catch(EOFException e) {
System.out.println("a client has been closed,can't read message from it.");
}
异常二
开启多个客户端,关闭一个客户端后,在其他客户端中再发出信息,服务器端会出现异常

这个问题是由
for(int i=0;i<clients.size();i++) {
Client c=clients.get(i);
c.send(str);
}
此处产生逻辑bug,当一个客户端被关闭之后,这个客户端还在clients集合当中,这个被关闭的客户端还要再执行send(str)发送信息
造成
private void send(String str) {
try {
dos.writeUTF(str);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
}
产生异常
解决异常,在集合中把这个客户端删除掉
catch(SocketException e) {
clients.remove(this);
}
服务器端完整代码如下:
package com.swift; import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.List; public class ChatServer { boolean started = false;
ServerSocket ss = null;
Socket s = null;
List<Client> clients=new ArrayList<Client>(); public static void main(String[] args) {
new ChatServer().fun();
} private void fun() {
try {
ss = new ServerSocket(8888);
started = true;
} catch (BindException e) {
System.out.println("端口使用中......");
} catch (IOException e1) {
e1.printStackTrace();
}
try {
while (started) {
s = ss.accept();
System.out.println("a client connected success");
Client c = new Client(s);
new Thread(c).start();
clients.add(c);
}
} catch (EOFException e) {
System.out.println("client has closed.");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} class Client implements Runnable { private Socket s;
private DataInputStream dis;
private DataOutputStream dos;
private boolean connected = false; public Client(Socket s) {
this.s = s;
try {
this.dis = new DataInputStream(s.getInputStream());
this.dos = new DataOutputStream(s.getOutputStream());
connected = true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void send(String str) {
try {
dos.writeUTF(str);
} catch(SocketException e) {
clients.remove(this);
} catch (IOException e) {
e.printStackTrace();
};
}
@Override
public void run() {
try {//注意:要包括while循环,如果try在while循环里,则出现socket closed异常
while (connected) {
String str = dis.readUTF();
System.out.println(str);
for(int i=0;i<clients.size();i++) {
Client c=clients.get(i);
c.send(str);
} // for(Iterator<Client> it=clients.iterator();it.hasNext();) {
// Client c=it.next();//方法二,不可取,有同步锁
// c.send(str);
// } // Iterator<Client> it=clients.iterator();
// while(it.hasNext()) {
// Client c=it.next();//方法三,不可取,有同步锁,修改需要加锁(此时没修改)
// c.send(str);
// } }
} catch(EOFException e) {
System.out.println("a client has been closed,can't read message from it.");
} catch (IOException e) {
e.printStackTrace();
} finally {
if (dis != null) {
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(dos!=null) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (s != null) {
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} } }
}
客户端完整代码如下:
package com.swift; import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ConnectException;
import java.net.Socket;
import java.net.SocketException; 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; public class ChatClientFrame extends JFrame { private static final long serialVersionUID = -118470059355655240L;
Socket s;
DataOutputStream dos;
DataInputStream dis;
private boolean connected = false;
JLabel label_shang = new JLabel();
JLabel label_xia = new JLabel();
JTextField tf = new JTextField(38);
JTextArea ta = new JTextArea(15, 50);
JButton button = new JButton(); public ChatClientFrame() {
setBounds(200, 200, 500, 400);
setTitle("客户端聊天工具 —— 1.0");
// 对窗口进行大的布局,分为三行一列,在pBasic面板上添加三个面板shang zhong xia
JPanel pBasic = new JPanel();
pBasic.setLayout(new BorderLayout());// 不设置默认也是这种布局模式
setContentPane(pBasic);// 把面板放在窗口上,不记得用this.关键字
JPanel shang = new JPanel();
JPanel zhong = new JPanel();
JPanel xia = new JPanel();
// 设置JPanel面板的大小
shang.setSize(470, 25);
zhong.setSize(470, 180);
xia.setSize(470, 40);
pBasic.add(shang, BorderLayout.NORTH);
pBasic.add(zhong, BorderLayout.CENTER);
pBasic.add(xia, BorderLayout.SOUTH);
shang.setBackground(Color.red);
zhong.setBackground(Color.yellow);
xia.setBackground(Color.blue); label_shang.setText("聊天记录");
shang.add(label_shang);
ta.setLineWrap(true);// 自动换行
JScrollPane scroll = new JScrollPane(ta);// 增加滚动条,以便不增加行数
zhong.add(scroll);
label_xia.setText("输入信息");
xia.add(label_xia, BorderLayout.WEST);
/*
* 增加功能,窗口监听事件,窗口打开时设置光标焦点在tf文本域中
*/
this.addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(WindowEvent e) {
tf.requestFocus();
}
});
xia.add(tf, BorderLayout.CENTER);
button.setText("发送");
xia.add(button, BorderLayout.EAST); button.addActionListener(new ShareListener());
tf.addActionListener(new ShareListener());
pack();
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
disconnect();
System.exit(0);
}
});
setVisible(true);
// 创建窗体直接调用连接服务器
connect();
Thread t=new Thread(new ReceiveThread());
t.start();
} class ShareListener implements ActionListener { @Override
public void actionPerformed(ActionEvent e) {
String tfText1 = tf.getText();
tf.setText("");
// 当回车或发送按钮时,tfText发送到服务器
try {
dos.writeUTF(tfText1);
dos.flush();
} catch (IOException e1) {
e1.printStackTrace();
} }
} class ReceiveThread implements Runnable { @Override
public void run() {
try {
while (connected) {
String str = dis.readUTF();
System.out.println(str);
ta.setText(ta.getText()+str+"\r\n");
}
} catch (SocketException e) {
System.out.println("a client has been closed!");
} catch (IOException e) {
e.printStackTrace();
}
} } public void connect() {
try {
s = new Socket("127.0.0.1", 8888);
System.out.println("connected!");
connected=true;
dos = new DataOutputStream(s.getOutputStream());
dis = new DataInputStream(s.getInputStream()); } catch (ConnectException e) {
System.out.println("服务端异常.........");
System.out.println("请确认服务端是否开启.........");
} catch (IOException e) {
e.printStackTrace();
}
} public void disconnect() {
try {
if (dos != null)
dos.close();
if(dis !=null)
dis.close();
if (s != null)
s.close();
} catch (IOException e) {
e.printStackTrace();
}
} public static void main(String[] args) {
new ChatClientFrame();
} }
java在线聊天项目1.0版 异常处理——开启多个客户端,关闭一个客户端后,在其他客户端中再发出信息会出现异常的处理的更多相关文章
- java在线聊天项目1.3版 ——设计好友列表框功能
设计好友列表框功能,思路—— 1.当客户端成功登陆后,则客户端把成功登陆信息发送给服务端, 2.由服务端将接收到来自各个成功登陆的客户端的用户信息添加进好友列表, 3.每当有成功登陆的用户就向各个客户 ...
- java在线聊天项目1.1版 ——开启多个客户端,分别实现注册和登录功能,使用客户端与服务端信息request机制,重构线程,将单独的登录和注册线程合并
实现效果图: eclipse项目中初步整合之前的各个客户端和服务端的窗口与工具类,效果如下图: 已将注册服务器线程RegServer功能放到LoginServer中,使用客户端与服务端的request ...
- java在线聊天项目1.2版 ——开启多个客户端,分别实现数据库注册和登录功能后,成功登陆则登录框消失,好友列表窗出现
登录框消失语句 dispose(); 好友列表窗出现 使用new FriendsFrame(phone,s); 登陆对话框代码修改如下: package com.swift.frame; import ...
- java在线聊天项目1.3版设计好友列表框功能补充,因只要用户登录就发送一串新列表,导致不同客户端好友列表不同问题
解决完毕后效果图: 好友列表Vector添加的时候进行判断,如果有相同的则不添加 int flag=0; for (int i = 0; i < names.size(); i++) { if ...
- 在线聊天项目1.4版 使用Gson方法解析Json字符串以便重构request和response的各种请求和响应 解决聊天不畅问题 Gson包下载地址
在线聊天项目结构图: 多用户登陆效果图: 多用户聊天效果图: 数据库效果图: 重新构建了Server类,使用了Gson方法,通过解析Json字符串,增加Info类,简化判断过程. Server类代码如 ...
- java在线聊天项目0.7版 连接多个客户端问题,开启多个客户端后服务器端只接收到一个 对各种异常的补充处理
问题的原因是 while(connected) { String str=dis.readUTF(); System.out.println(str); } 不断循环执行,一直在死循环获取socket ...
- java在线聊天项目 客户端登陆窗口LoginDialog的注册用户功能 修改注册逻辑 增空用户名密码的反馈 增加showMessageDialog()提示框
LoginDialog类的代码修改如下: package com.swift.frame; import java.awt.EventQueue; import java.awt.event.Acti ...
- java在线聊天项目 swt可视化窗口Design 登录框注册按钮点击改变窗口大小——出现注册面板 实现打开登录框时屏幕居中
登录框注册按钮点击改变窗口大小——出现注册面板 首先用swt可视化设计登录窗口如下图: 此时窗口高度为578 没点击注册时高度为301(可自己定) 注意:注册用户的Jpanel 的border选择T ...
- java在线聊天项目 实现基本聊天功能后补充的其他功能详细需求分析 及所需要掌握的Java知识基础 SWT的激活方法,swt开发包下载,及破解激活码
补充聊天项目功能,做如下需求分析: 梳理项目开发所需的必要Java知识基础 GUI将使用更快速的swt实现 SWT(Standard Widget Toolkit) Standard Widget T ...
随机推荐
- atcoder057D(组合数模板)
题目链接:http://abc057.contest.atcoder.jp/tasks/abc057_d 题意:给出n个数,可以选择x~y个数,使其平均值最大,求其最大平均数以及选择方案数. 思路:只 ...
- Mybatis源码解读-设计模式总结
虽然我们都知道有26个设计模式,但是大多停留在概念层面,真实开发中很少遇到,Mybatis源码中使用了大量的设计模式,阅读源码并观察设计模式在其中的应用,能够更深入的理解设计模式. Mybatis至少 ...
- 解决element 照片墙上传时回显问题
1.先看看样式: <el-upload class="imgList" action="1165165" list-type="picture- ...
- QuantLib 金融计算——基本组件之 ExchangeRateManager 类
目录 QuantLib 金融计算--基本组件之 ExchangeRateManager 类 概述 Money 类中的汇率转换配置 ExchangeRateManager 函数 如果未做特别说明,文中的 ...
- 区间质数查询 luoguP1865
原题 https://www.luogu.org/problemnew/show/P1865 本来get到了一个很好的判断素数的方法 O(玄学常数)https://www.luogu.org/blog ...
- Tomcat日志文件的输出在Linux和Windows下的差异
前言 最近老大发现Tomcat的日志文件catalina.out里存在着大量的和公司项目相关的log信息,因为一般都是会使用日志框架并另外将log信息输出到另外的文件里的,catalina.out文件 ...
- Vue文件 引入.js文件 的组件
Vue.component('remote-script', { render: function (createElement) { var self = this; return createEl ...
- github 收藏项目的方法
1,Watching 需要收藏的项目 2,查看收藏的项目
- python异常之ModuleNotFoundError: No module named 'test01inner02'
当我们使用sys.path.append(args) 指令向程序中导入模块时其实本次append操作只是在内存中完成的,如果要永久性的添加需要修改环境变量. 我们发现当我们使用print(sys.pa ...
- Codeforces 1137D(技巧)
一开始写的第一步让0和1一起走然后第二步再让0走会挂最后一个点--然后探索一下觉得主要问题在于我模拟的一步一步地走.如果这样的话9 2这个数据会使第17步他俩就碰在final点了,而实际上我们想要的效 ...