异常一

只开启一个客户端,输入信息后关闭,客户端出现如下异常

根据异常说明 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版 异常处理——开启多个客户端,关闭一个客户端后,在其他客户端中再发出信息会出现异常的处理的更多相关文章

  1. java在线聊天项目1.3版 ——设计好友列表框功能

    设计好友列表框功能,思路—— 1.当客户端成功登陆后,则客户端把成功登陆信息发送给服务端, 2.由服务端将接收到来自各个成功登陆的客户端的用户信息添加进好友列表, 3.每当有成功登陆的用户就向各个客户 ...

  2. java在线聊天项目1.1版 ——开启多个客户端,分别实现注册和登录功能,使用客户端与服务端信息request机制,重构线程,将单独的登录和注册线程合并

    实现效果图: eclipse项目中初步整合之前的各个客户端和服务端的窗口与工具类,效果如下图: 已将注册服务器线程RegServer功能放到LoginServer中,使用客户端与服务端的request ...

  3. java在线聊天项目1.2版 ——开启多个客户端,分别实现数据库注册和登录功能后,成功登陆则登录框消失,好友列表窗出现

    登录框消失语句 dispose(); 好友列表窗出现 使用new FriendsFrame(phone,s); 登陆对话框代码修改如下: package com.swift.frame; import ...

  4. java在线聊天项目1.3版设计好友列表框功能补充,因只要用户登录就发送一串新列表,导致不同客户端好友列表不同问题

    解决完毕后效果图: 好友列表Vector添加的时候进行判断,如果有相同的则不添加 int flag=0; for (int i = 0; i < names.size(); i++) { if ...

  5. 在线聊天项目1.4版 使用Gson方法解析Json字符串以便重构request和response的各种请求和响应 解决聊天不畅问题 Gson包下载地址

    在线聊天项目结构图: 多用户登陆效果图: 多用户聊天效果图: 数据库效果图: 重新构建了Server类,使用了Gson方法,通过解析Json字符串,增加Info类,简化判断过程. Server类代码如 ...

  6. java在线聊天项目0.7版 连接多个客户端问题,开启多个客户端后服务器端只接收到一个 对各种异常的补充处理

    问题的原因是 while(connected) { String str=dis.readUTF(); System.out.println(str); } 不断循环执行,一直在死循环获取socket ...

  7. java在线聊天项目 客户端登陆窗口LoginDialog的注册用户功能 修改注册逻辑 增空用户名密码的反馈 增加showMessageDialog()提示框

    LoginDialog类的代码修改如下: package com.swift.frame; import java.awt.EventQueue; import java.awt.event.Acti ...

  8. java在线聊天项目 swt可视化窗口Design 登录框注册按钮点击改变窗口大小——出现注册面板 实现打开登录框时屏幕居中

    登录框注册按钮点击改变窗口大小——出现注册面板  首先用swt可视化设计登录窗口如下图: 此时窗口高度为578 没点击注册时高度为301(可自己定) 注意:注册用户的Jpanel 的border选择T ...

  9. java在线聊天项目 实现基本聊天功能后补充的其他功能详细需求分析 及所需要掌握的Java知识基础 SWT的激活方法,swt开发包下载,及破解激活码

    补充聊天项目功能,做如下需求分析: 梳理项目开发所需的必要Java知识基础 GUI将使用更快速的swt实现 SWT(Standard Widget Toolkit) Standard Widget T ...

随机推荐

  1. vant搜索框问题

    最近使用vant搜索框时发现,当输入内容点击一次搜索有数据,点击错号把内容去掉再点击搜索,都没进入点击搜索方法. 解决方法:把bindtop改成bindtouchstart <van-searc ...

  2. 慕课笔记-Java入门第三季

    1.自定义异常 自定义异常必须继承Exception类或者其子类. 2.字符串 String对象创建后则不能被修改,是不可变的,所谓的修改其实是创建了新的对象. 多次创建的字符常量,Java编译程序只 ...

  3. Validation(4)-临时

    使用Hibernate-Validator优雅的校验参数 2019年01月01日 13:17:31 余生之君 阅读数:337    版权声明:本文为博主原创文章,未经博主允许不得转载. https:/ ...

  4. mybatis-trim标签说明

    trim标签使用1.trim 有四个属性 2.prefix,suffix 表示在trim标签包裹的部分的前面或者后面添加内容(注意:是没有prefixOverrides,suffixOverrides ...

  5. PostgreSQL - 模糊查询

    前言 like.not like在SQL中用于模糊查询,%表示任意个字符,_表示单个任意字符,如果需要在模糊查询中查询这两个通配符,需要用ESCAPE进行转义,如下: select * from ta ...

  6. RDS 导出Mysqlbinlog_二进制日志

    1:首先进入RDS后台查看Mysqlbin_log日志,可以通过以下命令进行查看: show master logs; 或 show binary logs; 2:比如我们获取的是:mysql-bin ...

  7. [題解](狀壓/水)luogu_P1879玉米田

    大水題然而因為智障的錯誤调了半天......n,m别反着输入啊......內外循環和狀態數都不等價 别的就是記錄一下每一行不可行的點,也狀壓一下,dp的時候判一下即可 #include<bits ...

  8. for循环 与 for in 循环

    json是js里的一种数据格式.var obj={a:15,b:8,c:12}         这是个json对象 var arr=[15,8,12]; 数组alert(obj.a); ---15al ...

  9. JS 两个数组合并

    让我们先考虑下面这情况: 代码如下: var a = [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ];var b = [ "foo", "bar", ...

  10. CSS div和css布局

    一.div和span DIV和SPAN在整个HTML标记中,没有任何意义,他们的存在就是为了应用CSS样式 DIV和span的区别在于,span是内联元素,div是块级元素.div占用整行,span只 ...