前段时间学校要求写java课程设计,当时有很多选题,那时候选了个学生成绩管理系统,不过自己对制作简单的聊天程序这个课题也是十分的感兴趣,从刚开始接触编程这一们技术的时候就很想写一个实现聊天功能的程序,于是乎前几天写了一个。在这个过程中发觉JavaSwing的socket编程感觉挺无力的(个人感觉,可能自己压根就没认识)。
以前认为实现socket这部分功能会很复杂,动手了才知道制作一个简单的聊天程序其实并不复杂(可能吧),不过说来也惭愧,当自己在本机和局域网内的电脑里运行这个程序是可以的,当时放到互联网上就不行了,个人感觉可能是端口映射的问题,可是将端口映射后还是没结果,于是这个小程序只能到此告一个段落了,虽然这次不是很成功,不过还是有点小收获的,这里稍微总结一下socket编写的过程:
(1)、ServerSocket server=new ServerSocket(端口号) // 服务端监听本地端口
(2)、Socket client=new Socket(服务端ip,端口号) //客户端建立与服务端的链接
(3)、Socket clientS=server.accept(); //服务端接受客户端的链接请求,这个是阻塞式的
(4)、连接建立成功,开始收发数据。
收发数据这一块需要使用到线程,因为要同时实现接收和发送数据,在线程当中使用死循环让程序一直处于工作状态,在收发数据这个也碰到了一个问题,自己也只使用了一个不大好的小技巧绕过,问题就是当程序两端某个用户退出程序另一端并不能马上知晓另一端断开了socket连接,在网络上找了一个办法,是说使用sendUrgentData判断另一端是否断开连接,因为默认情况下如果连接成功,对方会自动舍弃该数据包。可是当自己使用到这个方法的时候出现了发送17次就会出错的问题,百度了一下貌似是系统的问题,没法解决。于是自己就想了个办法在程序的退出函数中加入了一条语句,当用户退出程序时就发送一条特殊的消息,对方程序接收到数据后就知道对方即将断开连接。不过其实还有一种还不错的解决方法,只不过不是实时的判断对方是否断开了连接,方法就是使用socket.getOutputStream和socket.getInputstream判断,当对方断开连接时进行收发数据会抛出异常,接受这个异常就好。
下面把我不成熟的代码放出来,记录一下,不过毫无借鉴价值
//服务端
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.DateFormat;
import java.util.Date;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.EmptyBorder;
public class MainWindow extends JFrame {
private JTextArea oldMsg;
private JTextArea newMsg;
private JMenuBar menuBar;
private JMenu item1;
private JMenuItem item11;
private JButton send;
private JButton clear;
private JScrollPane scrollPane;
private JPanel panel1;
private JPanel panel2;
private File f;
private Date time;
private DateFormat df;
private String newStr;
private PopupMenu pop;
private MenuItem pItem1;
private String temp;
private ServerSocket server;
private Socket socket;
private String ip;
private String s;
private int flag = 0;
MainWindow() {
Container c = this.getContentPane();
c.setLayout(new BorderLayout());
pop = new PopupMenu();
pItem1 = new MenuItem("清空");
pItem1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
oldMsg.setText("");
}
});
pop.add(pItem1);
oldMsg = new JTextArea();
oldMsg.setEditable(false);
oldMsg.setLineWrap(true);
oldMsg.add(pop);
oldMsg.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
showPopmenu(e);
}
});
newMsg = new JTextArea();
newMsg.setLineWrap(true);
// menuBar = new JMenuBar();
// item1 = new JMenu("设置");
// item11 = new JMenuItem("IP设置");
// item11.addActionListener(new ActionListener() {
// @Override
// public void actionPerformed(ActionEvent arg0) {
// setOldMsg();
// }
// });
df = DateFormat.getDateTimeInstance();
send = new JButton("发送");// 重要的部分
send.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
if (socket == null) {
JOptionPane.showMessageDialog(null, "没有客户端连接", "错误", 1, null);
return;
}
temp = newMsg.getText();
if (temp.equals(""))
return;
// 向客户端发送数据
try {
PrintWriter pw;
pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
pw.println(temp);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 修改本地记录
addNewMsg anm = new addNewMsg("--->(You)", temp);
Thread t = new Thread(anm);
t.start();
newMsg.setText("");
}
});
clear = new JButton("清除");
clear.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
newMsg.setText("");
}
});
scrollPane = new JScrollPane(oldMsg);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
panel1 = new JPanel();
panel2 = new JPanel();
panel1.setLayout(new BorderLayout());
panel1.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
panel2.setLayout(new GridLayout(2, 1, 5, 5));
panel2.setBorder(new EmptyBorder(1, 1, 1, 1));
panel2.add(send);
panel2.add(clear);
panel1.add(BorderLayout.CENTER, newMsg);
panel1.add(BorderLayout.EAST, panel2);
c.add(BorderLayout.CENTER, scrollPane);
c.add(BorderLayout.SOUTH, panel1);
// item1.add(item11);
// menuBar.add(item1);
// this.setJMenuBar(menuBar);
Toolkit tk = getToolkit();
Dimension dm = tk.getScreenSize();
int width = 400;
int height = 500;
this.setBounds((int) (dm.getWidth() - width) / 2, (int) (dm.getHeight() - height) / 2, width, height);
this.setMinimumSize(new Dimension(300, 300));
this.addWindowListener(new windowLis());
this.setVisible(true);
oldMsg.setCaretPosition(oldMsg.getText().length());
try {
server = new ServerSocket(8086);
// waitConnect();
p a = new p();
Thread ttt = new Thread(a);
ttt.start();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
class windowLis extends WindowAdapter {
@Override
public void windowClosing(WindowEvent e) {
try {
if (socket != null) {
PrintWriter pw;
pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
pw.println("!@#$%^&*()");
}
System.exit(0);
} catch (IOException e1) {
}
}
}
// 显示历史消息
void setOldMsg() {
try {
oldMsg.setText("");
String str;
BufferedReader br = new BufferedReader(new FileReader(f));
while ((str = br.readLine()) != null) {
oldMsg.append(str + '\n');
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 获取文件操作对象
void getFileInstance(String sstr) {
time = new Date();
DateFormat ddf = DateFormat.getDateInstance();
String str = "./" + sstr.replace('.', '_') + '_' + ddf.format(time).replace('-', '_') + ".txt";
f = new File(str);
try {
if (!f.exists()) {
f.createNewFile();
}
} catch (Exception e) {
System.out.println("error");
}
}
// 消息记录框弹出菜单
void showPopmenu(MouseEvent e) {
int mods = e.getModifiers();
if (e.getButton() == MouseEvent.BUTTON3) {
pop.show(oldMsg, e.getX(), e.getY());
}
}
class p implements Runnable {
@Override
public void run() {
while (true) {
if (flag == 0) {
waitConnect();
flag = 1;
}
}
}
}
// 创建连接
void waitConnect() {
try {
socket = server.accept();
ip = socket.getInetAddress().getHostAddress();
getFileInstance(ip);
// 监听
listenClient lc = new listenClient();
Thread t2 = new Thread(lc);
t2.start();
setTitle("连接到:" + ip);
getFileInstance(ip);
setOldMsg();
oldMsg.setCaretPosition(oldMsg.getText().length());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 监听客户端
class listenClient implements Runnable {
private BufferedReader br;
int n = 1;
@Override
public void run() {
while (true) {
if (socket.isConnected()) {
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
if (br.ready()) {
s = br.readLine();
if (s.equals("!@#$%^&*()")) {
setTitle("未连接");
JOptionPane.showMessageDialog(null, "客户端关闭了连接", "错误", 1, null);
socket = null;
waitConnect();
break;
}
addNewMsg a = new addNewMsg(("--->" + ip), s);
Thread tt = new Thread(a);
tt.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
// 修改聊天记录
class addNewMsg implements Runnable {
String who;
String msg;
addNewMsg(String who, String msg) {
this.who = who;
this.msg = msg;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
FileWriter fw;
time = new Date();
newStr = who + " " + df.format(time) + '\n' + " " + msg + '\n';
oldMsg.append(newStr);
oldMsg.setCaretPosition(oldMsg.getText().length());
fw = new FileWriter(f, true);
PrintWriter pw = new PrintWriter(fw);
pw.println(newStr);
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//客户端
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.DateFormat;
import java.util.Date;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.EmptyBorder;
public class MainWindow extends JFrame {
private JTextArea oldMsg;
private JTextArea newMsg;
private JMenuBar menuBar;
private JMenu item1;
private JMenuItem item11;
private JButton send;
private JButton clear;
private JScrollPane scrollPane;
private JPanel panel1;
private JPanel panel2;
private File f;
private Date time;
private DateFormat df;
private String newStr;
private PopupMenu pop;
private MenuItem pItem1;
private String temp;
private Socket socket;
private String s;
private String ip;
private Thread lisThread;
MainWindow() {
getFileInstance();
Container c = this.getContentPane();
c.setLayout(new BorderLayout());
pop = new PopupMenu();
pItem1 = new MenuItem("清空");
pItem1.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
oldMsg.setText("");
}
});
pop.add(pItem1);
oldMsg = new JTextArea();
oldMsg.setEditable(false);
oldMsg.setLineWrap(true);
oldMsg.add(pop);
oldMsg.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
showPopmenu(e);
}
});
setOldMsg();
newMsg = new JTextArea();
newMsg.setLineWrap(true);
menuBar = new JMenuBar();
item1 = new JMenu("设置");
item11 = new JMenuItem("IP设置");
item11.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
getFileInstance();
setOldMsg();
}
});
df = DateFormat.getDateTimeInstance();
send = new JButton("发送");// 重要的部分
send.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
temp = newMsg.getText();
if (temp.equals(""))
return;
// 向服务端发送数据
try {
PrintWriter pw;
pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
pw.println(temp);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
addNewMsg anm = new addNewMsg("--->(You)", temp);
Thread t = new Thread(anm);
t.start();
newMsg.setText("");
}
});
clear = new JButton("清除");
clear.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
newMsg.setText("");
}
});
scrollPane = new JScrollPane(oldMsg);
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
panel1 = new JPanel();
panel2 = new JPanel();
panel1.setLayout(new BorderLayout());
panel1.setBorder(BorderFactory.createLineBorder(Color.GRAY, 1));
panel2.setLayout(new GridLayout(2, 1, 5, 5));
panel2.setBorder(new EmptyBorder(1, 1, 1, 1));
panel2.add(send);
panel2.add(clear);
panel1.add(BorderLayout.CENTER, newMsg);
panel1.add(BorderLayout.EAST, panel2);
c.add(BorderLayout.CENTER, scrollPane);
c.add(BorderLayout.SOUTH, panel1);
item1.add(item11);
menuBar.add(item1);
this.setJMenuBar(menuBar);
Toolkit tk = getToolkit();
Dimension dm = tk.getScreenSize();
int width = 400;
int height = 500;
this.setBounds((int) (dm.getWidth() - width) / 2, (int) (dm.getHeight() - height) / 2, width, height);
this.setMinimumSize(new Dimension(300, 300));
this.addWindowListener(new windowLis());
this.setVisible(true);
oldMsg.setCaretPosition(oldMsg.getText().length());
listenClient lc = new listenClient();
lisThread = new Thread(lc);
lisThread.start();
}
class windowLis extends WindowAdapter {
@Override
public void windowClosing(WindowEvent e) {
try {
PrintWriter pw;
pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
pw.println("!@#$%^&*()");
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.exit(0);
}
}
// 显示历史消息
void setOldMsg() {
try {
oldMsg.setText("");
String str;
BufferedReader br = new BufferedReader(new FileReader(f));
while ((str = br.readLine()) != null) {
oldMsg.append(str + '\n');
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 获取文件操作对象
void getFileInstance() {
try {
IPWindow iw = new IPWindow();
ip = iw.getIP();
if(socket!=null){
PrintWriter pw;
pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
pw.println("!@#$%^&*()");
}
socket = new Socket(ip, 8086);
f = iw.getFile();
} catch (UnknownHostException e) {
} catch (IOException e) {
JOptionPane.showMessageDialog(null, "未找到主机", "错误", 1, null);
System.exit(0);
}
}
// 消息记录框弹出菜单
void showPopmenu(MouseEvent e) {
int mods = e.getModifiers();
if (e.getButton() == MouseEvent.BUTTON3) {
pop.show(oldMsg, e.getX(), e.getY());
}
}
// 监听服务端
class listenClient implements Runnable {
private BufferedReader br;
private InputStreamReader isr;
@Override
public void run() {
while (true) {
if (socket.isConnected()) {
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
if (br.ready()) {
s = br.readLine();
if(s.equals("!@#$%^&*()")){
setTitle("未连接");
JOptionPane.showMessageDialog(null, "主机关闭了连接", "错误", 1, null);
System.exit(0);;
}
addNewMsg a = new addNewMsg(("--->" + ip), s);
Thread tt = new Thread(a);
tt.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
// 修改聊天记录
class addNewMsg implements Runnable {
String who;
String msg;
addNewMsg(String who, String msg) {
this.who = who;
this.msg = msg;
}
@Override
public void run() {
try {
FileWriter fw;
time = new Date();
newStr = who + " " + df.format(time) + '\n' + " " + msg + '\n';
oldMsg.append(newStr);
oldMsg.setCaretPosition(oldMsg.getText().length());
fw = new FileWriter(f, true);
PrintWriter pw = new PrintWriter(fw);
pw.println(newStr);
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//IPWindow
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.text.DateFormat;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
public class IPWindow extends JDialog {
private JLabel Lip;
private JTextField Tip;
private JButton confirm;
private JPanel panel1;
private JPanel panel2;
private File f;
private Date time;
private DateFormat df;
IPWindow() {
Container c = this.getContentPane();
c.setLayout(new GridLayout(2, 1));
Lip = new JLabel("输入对方ip:");
Tip = new JTextField();
df = DateFormat.getDateInstance();
confirm = new JButton("确定");
confirm.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
if(!isIP(Tip.getText())){
JOptionPane.showMessageDialog(null, "错误的ip格式", "错误", 1, null);
return;
}
time = new Date();
String str = "./" + Tip.getText().replace('.', '_') + '_' + df.format(time).replace('-', '_') + ".txt";
f = new File(str);
try {
if (!f.exists()) {
f.createNewFile();
}
} catch (Exception e) {
System.out.println("error");
}
dispose();
}
});
panel1 = new JPanel();
panel2 = new JPanel();
panel1.setLayout(new BorderLayout());
panel1.setBorder(new EmptyBorder(3, 3, 3, 3));
panel1.add(BorderLayout.WEST, Lip);
panel1.add(BorderLayout.CENTER, Tip);
panel2.add(confirm);
c.add(panel1);
c.add(panel2);
Toolkit tk = getToolkit();
Dimension dm = tk.getScreenSize();
int width = 300;
int height = 100;
this.setBounds((int) (dm.getWidth() - width) / 2, (int) (dm.getHeight() - height) / 2, width, height);
this.setResizable(false);
this.setModal(true);
this.addWindowListener(new windowLis());
this.setVisible(true);
}
File getFile() {
return f;
}
String getIP(){
return Tip.getText();
}
class windowLis extends WindowAdapter {
@Override
public void windowClosing(WindowEvent e) {
// TODO Auto-generated method stub
System.exit(0);
}
}
public boolean isIP(String addr) {
if (addr.length() < 7 || addr.length() > 15 || "".equals(addr))
return false;
String rexp = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}";
Pattern pat = Pattern.compile(rexp);
Matcher mat = pat.matcher(addr);
boolean ipAddress = mat.find();
return ipAddress;
}
}