本次实验涉及的知识点
1、掌握网络编程的基本概念。
2、掌握java.net包中常用网络编程工具类的功能和使用。
3、掌握UDP编程和TCP编程的基本方法和步骤。
结合图形界面、IO操作、网络编程知识,设计一个简单聊天室程序,要求能够实现两台电脑之间的对聊。
实现效果如下:
这个程序基本功能差不多都能实现,但还是有几个BUG,我不知道怎么改,望有大佬可以帮忙看看,给我提提意见,谢谢!
BUG有以下几点:
1、在界面布局方面,如图2程序结果显示的中间那块白色的文本域计划用来作为用户输入发送内容的区域,可是不知为何这个文本域的输入内容没办法显示出来,我现在也不知道是哪里出了问题没有办法解决;
2、在程序刚开始就会弹出的一个端口号的界面,这个界面的作用是让用户输入他们想要聊天的目标端口号,使得程序能够监听到该端口,出现的问题是这个界面一开始会持续报错,使用户没有办法正常输入端口号,对此,我的解决办法是在端口号这个界面中使用BorderLayout布局,将三个组件按照上中下放至,并对按钮组件新建事件来处理用户输入的端口号,这个问题就能解决;
3、这个程序有些不太稳定,如图1所示,界面整体布局很不稳定,程序刚开始作为会话窗口的文本域无法显示,但成功发送第一条信息后却又成功显示出来,而界面顶部的标志当前程序端口号的label也一直无法正常显示。
希望有大神可以帮忙解决!谢谢啦~
package 实验报告五_聊天室;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class View {
private static int sendport=123;//本机端口号
//新建各种界面布局所需组件
public static JFrame jf=new JFrame("JT聊天室");//创建新窗口
public static JLabel label1 = new JLabel("IP:");
public static JLabel label2 = new JLabel("端口号:");
public static JLabel label3 = new JLabel("请输入端口号:");
public static JLabel stateL = new JLabel("本端口号为"+sendport);
public static JTextField ip = new JTextField(10);
public static JTextField port = new JTextField(10);
public static JTextField rport = new JTextField(5);
public static JButton button1 = new JButton("发送");
public static JButton button2 = new JButton("清屏");
public static JButton button3 = new JButton("确认");
public static JPanel send = new JPanel();
public static JPanel state = new JPanel();
public static JPanel end = new JPanel();
public static JTextArea hhck = new JTextArea(16,40);
public static JTextArea fsnr = new JTextArea(50,5);
public static DatagramSocket data;
public static JDialog dkh = new JDialog(jf,"端口号",true);
public static JScrollPane jsp = new JScrollPane(hhck);
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
conversation();
}
});
send();
reveice();
}
private static void send() {
button1.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
//获取发送目标的IP以及端口号
String rip = ip.getText();
String rport = port.getText();
//判断目标IP及端口号是否为空
if(rip==null||rip.trim().equals("")||rport==null||rport.trim().equals("")){
JOptionPane.showMessageDialog(hhck, "请输入IP地址和端口号");
return;
}
if(data==null||data.isClosed()){
JOptionPane.showMessageDialog(hhck, "监听失败!");
return;
}
//获得发送内容
String nr = fsnr.getText();
byte[] buf = nr.getBytes();
try {
hhck.append("我对"+rip+":"+rport+"说:\n"+nr+"\n");
//添加内容后,是滚动条自动滚动到最底端
hhck.setCaretPosition(hhck.getText().length());
//发送内容
data.send(new DatagramPacket(buf,buf.length,InetAddress.getByName(rip),Integer.parseInt(rport)));
fsnr.setText("");
} catch (IOException e1) {
JOptionPane.showMessageDialog(hhck, "出错了,发送不成功!");
e1.printStackTrace();
}
}
});
button2.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
hhck.setText("");//清空聊天记录内容
}
});
}
private static void reveice() {
button3.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
//为“确认”按钮新建事件
int port = sendport;
while(true){
try {
if(data!=null && !data.isClosed()){
data.close();
}
try {
port=Integer.parseInt(rport.getText());
if(port<1||port>65535){
throw new RuntimeException("端口号超出范围");
}
} catch (Exception e1) {
JOptionPane.showMessageDialog(null, "你输入的端口不正确,请输入1-65535之间的数");
continue;
}
data = new DatagramSocket(sendport);
startListen();
stateL.setText("已在"+port+"端口监听");
dkh.setVisible(false);
break;
} catch (SocketException e1) {
// 端口号被占用需重新填写
label3.setText("端口已被占用,请重新设置端口:");
stateL.setText("本端口号为"+sendport);
dkh.setVisible(true);
}
}
}
});
}
private static void startListen() {
// 开启新线程实现接收信息
new Thread(){
private DatagramPacket p;
public void run(){
byte[] buf = new byte[1024];
p = new DatagramPacket(buf,buf.length);
while(!data.isClosed()){
try {
data.receive(p);
String s = new String(p.getData(),0,p.getLength());
hhck.append(p.getAddress().getHostAddress()+":"+p.getPort()+"对我说:\n"+s+"\n");
//添加内容后,是滚动条自动滚动到最底端
hhck.setCaretPosition(hhck.getText().length());
} catch (IOException e) {
e.printStackTrace();
}
}
}
}.start();
}
protected static void conversation() {
//Scanner s =new Scanner(System.in);
// 实现输入端口号视窗界面
dkh.setSize(500, 500);
dkh.setLocation(800, 600);
dkh.setLayout(new BorderLayout());
dkh.add(label3,BorderLayout.PAGE_START);
dkh.add(rport,BorderLayout.CENTER);
dkh.add(button3,BorderLayout.PAGE_END);
dkh.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
// 实现聊天室视窗界面
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭窗口时,一同结束后台程序。
jf.setSize(700,500);
jf.setLocation(400,200);
jf.setResizable(false);//设置窗口大小不可调整
jf.setVisible(true);//设置窗体可见
jf.setLayout(new BorderLayout());//设置布局格式
hhck.setBackground(new Color(211,211,211));//设置会话窗口背景颜色
hhck.setEditable(false);//设置会话窗口不可编辑
//将文本框与按钮放至同一Panel面板中
send.add(label1);
send.add(ip);
send.add(label2);
send.add(port);
send.add(button1);
send.add(button2);
//将内容输入文本域和send面板放至同一个Panel中
end.setLayout(new BorderLayout());
end.add(fsnr,BorderLayout.CENTER);
end.add(send,BorderLayout.PAGE_END);
//将会话窗口与顶部显示栏放至同一个Panel中
stateL.setHorizontalAlignment(JLabel.RIGHT);
state.setLayout(new BorderLayout());
state.add(stateL,BorderLayout.PAGE_START);
state.add(jsp,BorderLayout.PAGE_END);
//将所有组件放入窗体jf
jf.add(state,BorderLayout.PAGE_START);
jf.add(end,BorderLayout.PAGE_END);
//输入端口号弹窗显示
dkh.setVisible(true);
}
}