基于TCP网络通信的简易多线程GUI聊天室
2015-10-06 16:29
260 查看
最近一段时间复习了一下JavaSE的内容,其中发现有不少纰漏。之后针对网络通信和多线程这一块,写了一下基于GUI的简易聊天室程序。
下面就是简单的一个GUI图,丑丑的。。不过基本的功能还是有的,可以简单做练手用。
之前一直弄不好的就是处理多线程和GUI的关系。我认为,要写出好的程序,一个好的架构是很必要的。(因为我自认不会从事前端设计,因此swing awt学习的甚少,只是做了基本了解)因此之前第一次写的时候自己都写糊涂了。之后,我列了一个提纲和简图,总算分清了每一个文件的功能。
1、ichat_server.java:server端的启动,初始化一个server端窗体。
4、ichat_server_sendthread.java:server客户端启动的发送线程,位于send按钮的响应函数下。
5、ichat_server_receivethread.java:上述提到的server端接收程序。
6、ichat_client.java:client端的启动部分,new一个client端窗体。和server端类似,不再赘述。
7、ichat_client_frame.java:client端窗体程序。
8、ichat_client_sendthread,java:client端发送线程,在send按钮的响应函数里。不再赘述。
9、ichat_client_receivethread.java:client端接收线程,连接server成功后即启动。不再赘述。
以上几大板块便是主要结构。在写的过程中,遇到了几个问题:
1、在线程中接收到了发送来的数据,但是不便于传回主窗体中修改窗体内容。因此我尝试过callable接口带图runnable接口,但是由于其内部的call()方法本身是阻塞的,因此也达不到我预期的效果。
2、比较重要的一点就是利用构造函数传递值。在我自己的写的过程中,我也遇到了传不了、获取 不了主窗体中控件的情况,最后发现是由于控件被定义为了private。。真是教训,以后一定记得住了。
下面再附上几张图吧:
服务器未打开时打开client端
服务器打开时打开client端
聊天界面
感觉之后可以添加的功能还是有很多的,还有线程的安全问题我也没有考虑,之后可以进一步改进。
版权声明:本文为博主原创文章,未经博主允许不得转载。
下面就是简单的一个GUI图,丑丑的。。不过基本的功能还是有的,可以简单做练手用。
之前一直弄不好的就是处理多线程和GUI的关系。我认为,要写出好的程序,一个好的架构是很必要的。(因为我自认不会从事前端设计,因此swing awt学习的甚少,只是做了基本了解)因此之前第一次写的时候自己都写糊涂了。之后,我列了一个提纲和简图,总算分清了每一个文件的功能。
1、ichat_server.java:server端的启动,初始化一个server端窗体。
public static void main(String[] args) { // TODO Auto-generated method stub ichat_client_frame mainframe = new ichat_client_frame(); mainframe.setVisible(true); mainframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); }2、ichat_server_frame.java:server端窗体的构建程序
private static final long serialVersionUID = 1L; private JLabel record_label = new JLabel("Chat Record:"); private JTextArea chat_record = new JTextArea(); private JTextArea text = new JTextArea(); private JButton send = new JButton("send"); private JButton open = new JButton("Open"); private ServerSocket server = null; private Socket client = null; private JScrollPane jsp = null; static List<Socket> clients = null;// 保存连接到服务器的客户端 public JTextArea getChatrecord() { return this.chat_record; } public JTextArea getTextcontent() { return this.text; } public ichat_server_frame() throws Exception { super(); this.setLayout(null); this.setResizable(false); this.setTitle("server"); record_label.setBounds(10, 10, 100, 20); chat_record.setLineWrap(true); text.setLineWrap(true); jsp = new JScrollPane(chat_record); jsp.setBounds(10, 30, 250, 200); text.setBounds(10, 240, 250, 80); send.setBounds(270, 240, 100, 40); send.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { new Thread(new ichat_server_sendthread(ichat_server_frame.this, client)).start(); // TODO Auto-generated method stub } }); open.setBounds(270, 280, 100, 40); open.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub try { server = new ServerSocket(8888); clients = new ArrayList<Socket>(); new Thread(new ichat_server_wait(ichat_server_frame.this, server, client)).start(); } catch (Exception e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } }); this.add(record_label); this.add(jsp); this.add(text); this.add(send); this.add(open); this.setSize(400, 380); this.setLocation(50, 50); }3、ichat_server_wait.java:进入等待线程。new一个等待线程的代码在Open按钮的响应函数中。在等待线程中接收客户端socket。一旦有连接,则new一个接收线程,不断接收客户端发过来的内容。
private ServerSocket server = null; private Socket client = null; private ichat_server_frame isf = null; public ichat_server_wait(ichat_server_frame isf, ServerSocket server, Socket client) throws Exception { // TODO Auto-generated constructor stub this.server = server; this.client = client; this.isf = isf; } @Override public void run() { // TODO Auto-generated method stub while (true) { try { client = server.accept(); ichat_server_frame.clients.add(client); new Thread(new ichat_server_receivethread(this.isf, this.client)) .start(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
4、ichat_server_sendthread.java:server客户端启动的发送线程,位于send按钮的响应函数下。
private ichat_server_frame isf = null; private Socket client = null; private BufferedWriter bw = null; public ichat_server_sendthread(ichat_server_frame isf, Socket client) { // TODO Auto-generated constructor stub this.isf = isf; this.client = client; } @Override public void run() { // TODO Auto-generated method stub if (isf.getTextcontent().getText().equals("")) { isf.getTextcontent().setText(""); isf.getChatrecord().append("Your input is NULL! \n"); } else { try { for (int i = 0; i < ichat_server_frame.clients.size(); i++) { client = ichat_server_frame.clients.get(i); bw = new BufferedWriter(new OutputStreamWriter( this.client.getOutputStream())); bw.write("Admin" + " : " + this.isf.getTextcontent().getText().toString()); bw.newLine(); bw.flush(); } isf.getChatrecord().append( "Admin" + " : " + this.isf.getTextcontent().getText() + "\n"); isf.getChatrecord().setCaretPosition( isf.getChatrecord().getText().length()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } isf.getTextcontent().setText(""); } }
5、ichat_server_receivethread.java:上述提到的server端接收程序。
private Socket client = null; public ichat_server_frame isf = null; public ichat_server_receivethread(ichat_server_frame isf, Socket client) { this.client = client; this.isf = isf; } @Override public void run() { // TODO Auto-generated method stub while (true) { BufferedReader br = null; BufferedWriter bw = null; String Line = null; try { br = new BufferedReader(new InputStreamReader( this.client.getInputStream())); while ((Line = br.readLine()) != null) { if (this.client.isClosed()) { break; } isf.getChatrecord().append(Line + "\n"); for (int i = 0; i < ichat_server_frame.clients.size(); i++) { Socket temp = ichat_server_frame.clients.get(i); bw = new BufferedWriter(new OutputStreamWriter( temp.getOutputStream())); bw.write(Line); // isf.getChatrecord().append(this.isf.getTextcontent().getText()); bw.newLine(); bw.flush(); } isf.getChatrecord().setCaretPosition( isf.getChatrecord().getText().length()); } br.close(); bw.close(); // client.close(); } catch (IOException e) { // TODO Auto-generated catch block try { br.close(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } break; } } }
6、ichat_client.java:client端的启动部分,new一个client端窗体。和server端类似,不再赘述。
7、ichat_client_frame.java:client端窗体程序。
private static final long serialVersionUID = 1L; private JLabel record_label = new JLabel("Chat Record:"); private JTextArea chat_record = new JTextArea(); private JTextArea text = new JTextArea(); private JButton send = new JButton("send"); private JButton connect = new JButton("connect"); private JLabel user_name = new JLabel("user name:"); private JTextField user_name_input = new JTextField("Tourist"); private JScrollPane jsp_client = null; private boolean flag_test_connect = false; private Socket client = null; public JTextField getUsername() { return this.user_name_input; } public JTextArea getChatrecord() { return this.chat_record; } public JTextArea getTextcontent() { return this.text; } public ichat_client_frame() { super(); try { client = new Socket("localhost", 8888); JOptionPane.showMessageDialog(this, "Connect successfully!"); new Thread(new ichat_client_receivethread(ichat_client_frame.this, client)).start(); this.flag_test_connect = true; connect.setEnabled(!flag_test_connect); } catch (Exception e1) { // TODO Auto-generated catch block JOptionPane.showMessageDialog(this, "Connect failed ! Maybe the server hadn't been launched!"); this.flag_test_connect = false; } this.setLayout(null); record_label.setBounds(10, 10, 100, 20); jsp_client = new JScrollPane(chat_record); jsp_client.setBounds(10, 30, 250, 200); text.setBounds(10, 240, 250, 80); send.setBounds(270, 240, 100, 40); connect.setBounds(270, 280, 100, 40); user_name.setBounds(270, 100, 100, 30); user_name_input.setBounds(270, 130, 100, 30); chat_record.setLineWrap(true); text.setLineWrap(true); this.setTitle("client"); send.setEnabled(flag_test_connect); send.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub new Thread(new ichat_client_sendthread(ichat_client_frame.this, client)).start(); } }); connect.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub try { client = new Socket("localhost", 8888); flag_test_connect = true; new Thread(new ichat_client_receivethread( ichat_client_frame.this, client)).start(); connect.setEnabled(!flag_test_connect); send.setEnabled(flag_test_connect); } catch (Exception e1) { // TODO Auto-generated catch block JOptionPane.showMessageDialog(ichat_client_frame.this, "Connect failed, the server hadn'd been launched!"); } } }); this.add(record_label); this.add(jsp_client); this.add(text); this.add(send); this.add(user_name); this.add(user_name_input); this.add(connect); this.setSize(400, 380); this.setLocation(500, 50); }
8、ichat_client_sendthread,java:client端发送线程,在send按钮的响应函数里。不再赘述。
9、ichat_client_receivethread.java:client端接收线程,连接server成功后即启动。不再赘述。
以上几大板块便是主要结构。在写的过程中,遇到了几个问题:
1、在线程中接收到了发送来的数据,但是不便于传回主窗体中修改窗体内容。因此我尝试过callable接口带图runnable接口,但是由于其内部的call()方法本身是阻塞的,因此也达不到我预期的效果。
2、比较重要的一点就是利用构造函数传递值。在我自己的写的过程中,我也遇到了传不了、获取 不了主窗体中控件的情况,最后发现是由于控件被定义为了private。。真是教训,以后一定记得住了。
下面再附上几张图吧:
服务器未打开时打开client端
服务器打开时打开client端
聊天界面
感觉之后可以添加的功能还是有很多的,还有线程的安全问题我也没有考虑,之后可以进一步改进。
版权声明:本文为博主原创文章,未经博主允许不得转载。
相关文章推荐
- 虚拟化Xen平台中,Dom0和DomU之间发送网络数据时各个部分所运行时间
- Android——使用Volley+fastJson在新线程中读取网络接口获取天气信息
- matlab 贝叶斯网络工具箱的安装
- http编程系列3:http协议POST方式提交数据并返回结果
- Http协议原理解析
- 《深入理解Linux网络技术内幕》阅读笔记(十六)
- HttpGet请求
- 20150924 Web Server(Http服务)
- http的报文结构和状态码的含义
- http的报文结构和状态码的含义
- 基于HTML5的3D网络拓扑树呈现
- TCP滑动窗口与回退N针协议
- 在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正确并且 SQL Server 已配置为允许远程连接。 (provider: 命名管
- 根据图片的网络URL获取Bitmap
- 301/302 http会话跳转
- Java Web添加HTTP服务
- TCP与UDP的区别
- TCP的三次握手和四次挥手
- netperf 而网络性能测量
- TCP的三次握手和四次挥手